T root() {
+ return (T) storage.root();
+ }
+
+ /**
+ * Sets the passed instance as the new root for the persistent object graph.
+ *
+ * @param object the new root object
+ * @return the new root object
+ */
+ public Object setRoot(final Object object) {
+ return storage.setRoot(object);
+ }
+
+ /**
+ * Stores the registered root instance.
+ *
+ * @return the root instance's objectId.
+ */
+ public long storeRoot() {
+ return storage.storeRoot();
+ }
+
+ /**
+ * Stores the passed object.
+ *
+ * @param object object to store
+ * @return the object id representing the passed instance.
+ */
+ public long store(final Object object) {
+ return storage.store(object);
+ }
+}
diff --git a/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/GreetingService.java b/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/GreetingService.java
new file mode 100644
index 00000000000..8bda36d76b6
--- /dev/null
+++ b/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/GreetingService.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.examples.integrations.eclipsestore.greetings.se;
+
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicReference;
+
+import io.helidon.config.Config;
+import io.helidon.http.Status;
+import io.helidon.integrations.eclipsestore.core.EmbeddedStorageManagerBuilder;
+import io.helidon.webserver.http.HttpRules;
+import io.helidon.webserver.http.HttpService;
+import io.helidon.webserver.http.ServerRequest;
+import io.helidon.webserver.http.ServerResponse;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArrayBuilder;
+import jakarta.json.JsonBuilderFactory;
+import jakarta.json.JsonObject;
+
+/**
+ * A simple service to greet you. Examples:
+ *
+ * Get default greeting message:
+ * curl -X GET http://localhost:8080/greet
+ *
+ * Get greeting message for Joe:
+ * curl -X GET http://localhost:8080/greet/Joe
+ *
+ * Change greeting:
+ * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}'
+ * http://localhost:8080/greet/greeting
+ *
+ * Get the logs:
+ * curl -X GET http://localhost:8080/greet/logs
+ *
+ * The message is returned as a JSON object
+ */
+
+public final class GreetingService implements HttpService {
+
+ /**
+ * Greeting reference.
+ */
+ private final AtomicReference greeting = new AtomicReference<>();
+
+ /**
+ * Json factory.
+ */
+ private static final JsonBuilderFactory JSON =
+ Json.createBuilderFactory(Collections.emptyMap());
+
+ /**
+ * Eclipse store context.
+ */
+ private final GreetingServiceEclipseStoreContext context;
+
+ /**
+ * Create greeting service.
+ * @param config configuration.
+ */
+ GreetingService(final Config config) {
+ greeting.set(
+ config.get("app.greeting").asString().orElse("Ciao"));
+
+ context = new GreetingServiceEclipseStoreContext(
+ EmbeddedStorageManagerBuilder.create(
+ config.get("eclipsestore")));
+ // we need to initialize the root element first
+ // if we do not wait here, we have a race where HTTP method
+ // may be invoked before we initialize root
+ context.start();
+ context.initRootElement();
+ }
+
+ @Override
+ public void routing(final HttpRules rules) {
+ rules.get("/", this::getDefaultMessageHandler)
+ .get("/logs", this::getLog)
+ .get("/{name}", this::getMessageHandler)
+ .put("/greeting", this::updateGreetingHandler);
+ }
+
+ private void getLog(final ServerRequest request,
+ final ServerResponse response) {
+ JsonArrayBuilder arrayBuilder = JSON.createArrayBuilder();
+ context.getLogs().forEach((entry) -> arrayBuilder.add(
+ JSON.createObjectBuilder()
+ .add("name", entry.name())
+ .add("time", entry.dateTime().toString())));
+ response.send(arrayBuilder.build());
+ }
+
+ /**
+ * Return a worldly greeting message.
+ *
+ * @param request the server request
+ * @param response the server response
+ */
+ private void getDefaultMessageHandler(final ServerRequest request,
+ final ServerResponse response) {
+ sendResponse(response, "World");
+ }
+
+ /**
+ * Return a greeting message using the name that was provided.
+ *
+ * @param request the server request
+ * @param response the server response
+ */
+ private void getMessageHandler(final ServerRequest request,
+ final ServerResponse response) {
+ String name = request.path().pathParameters().get("name");
+ sendResponse(response, name);
+ }
+
+ private void sendResponse(final ServerResponse response,
+ final String name) {
+ String msg = String.format("%s %s!", greeting.get(), name);
+
+ context.addLogEntry(name);
+
+ JsonObject returnObject = JSON.createObjectBuilder()
+ .add("message", msg)
+ .build();
+ response.send(returnObject);
+ }
+
+ private void updateGreetingFromJson(final JsonObject jo,
+ final ServerResponse response) {
+ if (!jo.containsKey("greeting")) {
+ JsonObject jsonErrorObject = JSON.createObjectBuilder()
+ .add("error", "No greeting provided")
+ .build();
+ response.status(Status.BAD_REQUEST_400)
+ .send(jsonErrorObject);
+ return;
+ }
+
+ greeting.set(jo.getString("greeting"));
+ response.status(Status.NO_CONTENT_204).send();
+ }
+
+ /**
+ * Set the greeting to use in future messages.
+ *
+ * @param request the server request
+ * @param response the server response
+ */
+ private void updateGreetingHandler(final ServerRequest request,
+ final ServerResponse response) {
+ JsonObject jsonObject = request.content().as(JsonObject.class);
+ updateGreetingFromJson(jsonObject, response);
+ }
+
+}
diff --git a/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/GreetingServiceEclipseStoreContext.java b/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/GreetingServiceEclipseStoreContext.java
new file mode 100644
index 00000000000..86d16479768
--- /dev/null
+++ b/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/GreetingServiceEclipseStoreContext.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.examples.integrations.eclipsestore.greetings.se;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
+
+/**
+ * This class extends {@link EclipseStoreExecutionContext}
+ * and provides data access methods.
+ */
+public class GreetingServiceEclipseStoreContext
+ extends EclipseStoreExecutionContext {
+
+ /**
+ * Create a new instance.
+ *
+ * @param storageManager the EmbeddedStorageManager used.
+ */
+ public GreetingServiceEclipseStoreContext(
+ final EmbeddedStorageManager storageManager) {
+ super(storageManager);
+ }
+
+ /**
+ * Add and store a new log entry.
+ *
+ * @param name parameter for log text.
+ */
+ @SuppressWarnings({"unchecked", "resource"})
+ public void addLogEntry(final String name) {
+ List logs = (List) storageManager().root();
+ logs.add(new LogEntry(name, LocalDateTime.now()));
+ storageManager().store(logs);
+ }
+
+ /**
+ * initialize the storage root with a new, empty List.
+ */
+ @SuppressWarnings("resource")
+ public void initRootElement() {
+ if (storageManager().root() == null) {
+ storageManager().setRoot(new ArrayList());
+ storageManager().storeRoot();
+ }
+ }
+
+ /**
+ * returns a List of all stored LogEntries.
+ *
+ * @return all LogEntries.
+ */
+ @SuppressWarnings({"unchecked", "resource"})
+ public List getLogs() {
+ return (List) storageManager().root();
+ }
+
+}
diff --git a/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/LogEntry.java b/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/LogEntry.java
new file mode 100644
index 00000000000..3012a8e5c66
--- /dev/null
+++ b/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/LogEntry.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.examples.integrations.eclipsestore.greetings.se;
+
+import java.time.LocalDateTime;
+
+
+/**
+ * Simple POJO that represents a Log entry that is stored by
+ * Eclipse store in this example.
+ */
+public final class LogEntry {
+
+ /**
+ * Name to be logged.
+ */
+ private final String name;
+
+ /**
+ * Date and time to be logged.
+ */
+ private final LocalDateTime dateTime;
+
+ /**
+ * @param aName name to be logged.
+ * @param aDateTime dateTime date and time to be logged
+ */
+ public LogEntry(final String aName, final LocalDateTime aDateTime) {
+ this.name = aName;
+ this.dateTime = aDateTime;
+ }
+
+ /**
+ * get the name.
+ *
+ * @return name
+ */
+ public String name() {
+ return name;
+ }
+
+
+ /**
+ * Get the date time.
+ *
+ * @return date time
+ */
+ public LocalDateTime dateTime() {
+ return dateTime;
+ }
+
+
+}
diff --git a/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/Main.java b/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/Main.java
new file mode 100644
index 00000000000..c1de8bcd9e0
--- /dev/null
+++ b/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/Main.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.examples.integrations.eclipsestore.greetings.se;
+
+import io.helidon.config.ClasspathConfigSource;
+import io.helidon.config.Config;
+import io.helidon.logging.common.LogConfig;
+import io.helidon.webserver.WebServer;
+import io.helidon.webserver.WebServerConfig;
+import io.helidon.webserver.http.HttpRouting;
+
+/**
+ * Eclipsestore demo with a simple rest application.
+ */
+public final class Main {
+
+ /**
+ * Cannot be instantiated.
+ */
+ private Main() {
+ }
+
+ /**
+ * Application main entry point.
+ *
+ * @param args command line arguments.
+ */
+ public static void main(final String[] args) {
+ WebServerConfig.Builder builder = WebServer.builder();
+ setup(builder);
+ WebServer server = builder.build().start();
+ System.out.println(
+ "WEB server is up! http://localhost:" + server.port() + "/greet");
+ }
+
+ static void setup(final WebServerConfig.Builder server) {
+ LogConfig.configureRuntime();
+ Config config =
+ Config.builder()
+ .addSource(ClasspathConfigSource.create("/application.yaml"))
+ .build();
+
+ // Build server with JSONP support
+ server.config(config.get("server"))
+ .routing(r -> routing(r, config));
+ }
+
+ /**
+ * Setup routing.
+ *
+ * @param routing routing builder
+ * @param config configuration of this server
+ */
+ static void routing(final HttpRouting.Builder routing,
+ final Config config) {
+ GreetingService greetService = new GreetingService(config);
+ routing.register("/greet", greetService);
+ }
+}
diff --git a/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/package-info.java b/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/package-info.java
new file mode 100644
index 00000000000..d26bf828763
--- /dev/null
+++ b/examples/integrations/eclipsestore/greetings-se/src/main/java/io/helidon/examples/integrations/eclipsestore/greetings/se/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * An example that uses Eclipsestore to persist a log entry for every greeting.
+ */
+package io.helidon.examples.integrations.eclipsestore.greetings.se;
diff --git a/examples/integrations/eclipsestore/greetings-se/src/main/resources/application.yaml b/examples/integrations/eclipsestore/greetings-se/src/main/resources/application.yaml
new file mode 100644
index 00000000000..55813458514
--- /dev/null
+++ b/examples/integrations/eclipsestore/greetings-se/src/main/resources/application.yaml
@@ -0,0 +1,26 @@
+#
+# Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+app:
+ greeting: "Hello"
+
+server:
+ port: 8080
+ host: 0.0.0.0
+
+eclipsestore:
+ channel-count: 4
+ housekeeping-interval: 2000ms
diff --git a/examples/integrations/eclipsestore/greetings-se/src/test/java/io/helidon/examples/integrations/eclipsestore/greetings/se/EclipseStoreExampleGreetingsSeTest.java b/examples/integrations/eclipsestore/greetings-se/src/test/java/io/helidon/examples/integrations/eclipsestore/greetings/se/EclipseStoreExampleGreetingsSeTest.java
new file mode 100644
index 00000000000..e2ee0899e3f
--- /dev/null
+++ b/examples/integrations/eclipsestore/greetings-se/src/test/java/io/helidon/examples/integrations/eclipsestore/greetings/se/EclipseStoreExampleGreetingsSeTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.examples.integrations.eclipsestore.greetings.se;
+
+import java.nio.file.Path;
+
+import io.helidon.webserver.testing.junit5.ServerTest;
+import io.helidon.webserver.testing.junit5.SetUpServer;
+import io.helidon.webclient.http1.Http1Client;
+import io.helidon.webclient.http1.Http1ClientResponse;
+import io.helidon.webserver.WebServerConfig;
+
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+@ServerTest
+public class EclipseStoreExampleGreetingsSeTest {
+
+ @TempDir
+ static Path tempDir;
+
+ private final Http1Client client;
+
+ public EclipseStoreExampleGreetingsSeTest(Http1Client client) {
+ this.client = client;
+ }
+
+ @SetUpServer
+ static void setup(WebServerConfig.Builder server) {
+ System.setProperty("eclipsestore.storage-directory", tempDir.toString());
+ Main.setup(server);
+ }
+
+ @Test
+ void testExample() {
+ try (Http1ClientResponse response = client.get("/greet/Joe").request()) {
+ assertThat(response.as(JsonObject.class).getString("message"), is("Hello Joe!"));
+ }
+
+ try (Http1ClientResponse response = client.get("/greet/logs").request()) {
+ JsonArray jsonArray = response.as(JsonArray.class);
+ assertThat(jsonArray.get(0).asJsonObject().getString("name"), is("Joe"));
+ assertThat(jsonArray.get(0).asJsonObject().getString("time"), notNullValue());
+ }
+ }
+}
diff --git a/examples/integrations/eclipsestore/pom.xml b/examples/integrations/eclipsestore/pom.xml
new file mode 100644
index 00000000000..198a220a816
--- /dev/null
+++ b/examples/integrations/eclipsestore/pom.xml
@@ -0,0 +1,38 @@
+
+
+
+ 4.0.0
+
+ io.helidon.examples.integrations
+ helidon-examples-integrations-project
+ 4.0.0-SNAPSHOT
+
+
+ io.helidon.examples.integrations.eclipsestore
+ helidon-examples-integrations-eclipsestore-project
+ Helidon Examples Integration EclipseStore
+ pom
+
+
+ greetings-se
+ greetings-mp
+
+
diff --git a/examples/integrations/pom.xml b/examples/integrations/pom.xml
index abead6217ee..9bbee7b7505 100644
--- a/examples/integrations/pom.xml
+++ b/examples/integrations/pom.xml
@@ -38,6 +38,7 @@
oci
vault
microstream
+ eclipsestore
diff --git a/integrations/eclipsestore/README.md b/integrations/eclipsestore/README.md
new file mode 100644
index 00000000000..4462f5c3bfa
--- /dev/null
+++ b/integrations/eclipsestore/README.md
@@ -0,0 +1,156 @@
+# Eclipse Store integration with Helidon
+
+This projects adds [Eclipse Store](https://https://eclipsestore.io/) support to Helidon.
+
+[Eclipse Store](https://eclipsestore.io/) is the successor of [Microstream](https://microstream.one), both of which are integrated into Helidon as
+extensions now, enabling smooth transition.
+
+The official [Eclipse Store documentation](https://docs.eclipsestore.io) can be found here.
+
+## helidon-integrations-eclipsestore
+
+Adds basic support for Eclipse Store
+
+### Prerequisites
+
+Use the following maven dependency
+
+```
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore
+
+```
+
+### API
+
+Use the EmbeddedStorageManagerBuilder to create a Eclipse Store instance:
+
+```
+EmbeddedStorageManager embeddedStorageManager = EmbeddedStorageManagerBuilder
+ .builder()
+ .build();
+```
+
+Configuration can either be done by the builders methods or by supplying a helidon configuration node
+
+```
+Config config = Config.create();
+
+EmbeddedStorageManager embeddedStorageManager = EmbeddedStorageManagerBuilder
+ .builder()
+ .config(config)
+ .build();
+```
+
+for a list of all possible properties
+see [Eclipse Store configuration properties](https://docs.eclipsestore.io/manual/storage/configuration/properties.html)
+
+### CDI extension for Eclipse Store
+
+the example below shows how to create a Eclipse Store instance using a provided configuration.
+
+```
+private EmbeddedStorageManager storage;
+
+@Inject
+public YourConstructor(@EclipseStoreStorage(configNode = "org.eclipse.store.storage.greetings")EmbeddedStorageManager storage) {
+ super();
+ this.storage = storage;
+}
+```
+
+## helidon-integrations-eclipsestore-cache
+
+Adds basic support for the Eclipse Store JCache implementation
+
+### Prerequisites
+
+Use the following maven dependency
+
+```
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore-cache
+
+```
+
+### API
+
+Use the CacheBuilder to create Eclipse Store JCache instance:
+
+Create a CacheConfiguration first
+
+```
+CacheConfiguration cacheConfig = EclipseStoreCacheConfigurationBuilder
+ .builder(config.get("cache"), Integer.class, String.class).build();
+```
+
+Then build the cache
+
+```
+Cache cache = CacheBuilder.builder(cacheConfig, Integer.class, String.class).build("myCache");
+```
+
+Configuration can either be done by the EclipseStoreCacheConfigurationBuilder or by supplying a helidon configuration node
+
+```
+Config config = Config.create();
+
+Cache cache = CacheBuilder.create("myCache", config, Integer.class, String.class);
+
+```
+
+for a list of all possible properties
+see [Eclipse Store Cache configuration properties](https://docs.eclipsestore.io)
+
+### CDI extension for Eclipse Store
+
+the example below shows how to create a Eclipse Store Cache instance using a provided configuration.
+
+```
+private Cache cache;
+
+@Inject
+public YourConstructor(@EclipseStoreCache(configNode = "org.eclipse.store.cache", name = "myCache") Cache cache) {
+ this.cache = cache;
+}
+```
+
+## helidon-integrations-eclipsestore-health
+
+This module provides helpers to create basic health checks for Eclipse Store
+
+### Prerequisites
+
+Use the following maven dependency
+
+```
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore-health
+
+```
+
+### Usage
+
+Register an instance of EclipseStoreHealthCheck to your server to provide a HealthCheck for a specific eclipse store instance.
+
+## helidon-integrations-eclipsestore-metrics
+
+This module provides helpers to create a set of default metrics for Eclipse Store
+
+### Prerequisites
+
+Use the following maven dependency
+
+```
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore-metrics
+
+```
+
+### Usage
+
+The EclipseStoreMetricsSupport class provides a set of default metrics
diff --git a/integrations/eclipsestore/cache/pom.xml b/integrations/eclipsestore/cache/pom.xml
new file mode 100644
index 00000000000..d52fe257bec
--- /dev/null
+++ b/integrations/eclipsestore/cache/pom.xml
@@ -0,0 +1,70 @@
+
+
+
+ 4.0.0
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore-project
+ 4.0.0-SNAPSHOT
+
+
+ helidon-integrations-eclipsestore-cache
+ Helidon Integrations Eclipse Store Cache
+ jar
+
+ Eclipse Store JCache implementation
+
+
+
+ org.eclipse.store
+ cache
+
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore
+
+
+ io.helidon.config
+ helidon-config-yaml
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ io.helidon.common.features
+ helidon-common-features-api
+
+
+
+
diff --git a/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/CacheBuilder.java b/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/CacheBuilder.java
new file mode 100644
index 00000000000..a66eb1c88cb
--- /dev/null
+++ b/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/CacheBuilder.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cache;
+
+import javax.cache.Caching;
+
+import io.helidon.config.Config;
+
+import org.eclipse.store.cache.types.Cache;
+import org.eclipse.store.cache.types.CacheConfiguration;
+import org.eclipse.store.cache.types.CacheManager;
+import org.eclipse.store.cache.types.CachingProvider;
+
+/**
+ * Builder for a Eclipse Store JCache instance.
+ *
+ * @param type of the cache key
+ * @param type of the cache value
+ */
+public class CacheBuilder {
+ private static final String ECLIPSESTORE_CACHING_PROVIDER = "org.eclipse.store.cache.types.CachingProvider";
+
+ private final CachingProvider provider;
+ private final CacheManager cacheManager;
+ private final CacheConfiguration configuration;
+
+ protected CacheBuilder(CacheConfiguration configuration) {
+ super();
+
+ this.configuration = configuration;
+ this.provider = (CachingProvider) Caching.getCachingProvider(ECLIPSESTORE_CACHING_PROVIDER);
+ this.cacheManager = provider.getCacheManager();
+ }
+
+ protected CacheBuilder(Class keyType, Class valueType) {
+ this.provider = (CachingProvider) Caching.getCachingProvider(ECLIPSESTORE_CACHING_PROVIDER);
+ this.cacheManager = provider.getCacheManager();
+ this.configuration = CacheConfiguration.Builder(keyType, valueType).build();
+ }
+
+ /**
+ * Create a new cache builder using the provided eclipstore cache configuration.
+ *
+ * @param type of the cache key
+ * @param type of the cache value
+ * @param configuration CacheConfiguration
+ * @param keyType class of the cache key
+ * @param valueType class of the cache key
+ * @return cache builder
+ */
+ public static CacheBuilder builder(CacheConfiguration configuration,
+ Class keyType,
+ Class valueType) {
+ return new CacheBuilder<>(configuration);
+ }
+
+ /**
+ * Create a named cache using the provided helidon configuration.
+ *
+ * @param name the cache name
+ * @param config the helidon configuration
+ * @param keyType class of the cache key
+ * @param valueType class of the cache key
+ * @return the new cache instance
+ */
+ public static Cache, ?> create(String name, Config config, Class> keyType, Class> valueType) {
+
+ CacheConfiguration, ?> cacheConfig = EclipseStoreCacheConfigurationBuilder.builder(config, keyType, valueType)
+ .build();
+ return new CacheBuilder<>(cacheConfig).build(name);
+ }
+
+ /**
+ * Set the name of the cache.
+ *
+ * @param name the cache name
+ * @return the new cache instance
+ */
+ public Cache build(String name) {
+ return cacheManager.createCache(name, configuration);
+ }
+}
diff --git a/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/ConfigException.java b/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/ConfigException.java
new file mode 100644
index 00000000000..3167c9e8253
--- /dev/null
+++ b/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/ConfigException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cache;
+
+import java.io.Serial;
+
+/**
+ * RuntimeException thrown in case of Eclipse Store Cache configuration problems.
+ */
+public class ConfigException extends RuntimeException {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * creates a new ConfigException.
+ *
+ * @param message exception message
+ * @param cause the cause
+ */
+ public ConfigException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * creates a new ConfigException.
+ *
+ * @param message exception message
+ */
+ public ConfigException(String message) {
+ super(message);
+ }
+
+}
diff --git a/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/EclipseStoreCacheConfigurationBuilder.java b/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/EclipseStoreCacheConfigurationBuilder.java
new file mode 100644
index 00000000000..de509279988
--- /dev/null
+++ b/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/EclipseStoreCacheConfigurationBuilder.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cache;
+
+import javax.cache.configuration.CacheEntryListenerConfiguration;
+import javax.cache.configuration.Factory;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheWriter;
+
+import io.helidon.config.Config;
+
+import org.eclipse.serializer.SerializerFoundation;
+import org.eclipse.serializer.configuration.types.Configuration;
+import org.eclipse.store.cache.types.CacheConfiguration;
+import org.eclipse.store.cache.types.CacheConfiguration.Builder;
+import org.eclipse.store.cache.types.CacheConfigurationBuilderConfigurationBased;
+import org.eclipse.store.cache.types.CacheConfigurationPropertyNames;
+import org.eclipse.store.cache.types.EvictionManager;
+
+
+
+/**
+ * Builder for Eclipse Store CacheConfigurations.
+ *
+ * @param type of the cache key
+ * @param type of the cache value
+ */
+public class EclipseStoreCacheConfigurationBuilder
+ implements CacheConfigurationPropertyNames,
+ CacheConfiguration.Builder,
+ io.helidon.common.Builder, CacheConfiguration> {
+
+ private final Builder cacheConfigBuilder;
+
+ protected EclipseStoreCacheConfigurationBuilder(Class keyType, Class valueType) {
+ super();
+ cacheConfigBuilder = CacheConfiguration.Builder(keyType, valueType);
+ }
+
+ protected EclipseStoreCacheConfigurationBuilder(Configuration configuration, Class keyType, Class valueType) {
+ super();
+ cacheConfigBuilder = CacheConfigurationBuilderConfigurationBased.New().buildCacheConfiguration(configuration,
+ CacheConfiguration.Builder(
+ keyType,
+ valueType));
+ }
+
+ /**
+ * creates a new EclipseStoreCacheConfigurationBuilder using the supplied helidon configuration.
+ *
+ * @param config helidon configuration
+ * @return a new EclipseStoreCacheConfigurationBuilder
+ */
+ public static EclipseStoreCacheConfigurationBuilder, ?> builder(Config config) {
+ return builder(config, null, null);
+ }
+
+ /**
+ * Create a CacheConfiguration builder with default values.
+ *
+ * @param type of the cache key
+ * @param type of the cache value
+ * @param keyType type of the cache key
+ * @param valueType type of the cache value
+ * @return a new CacheConfiguration builder
+ */
+ public static EclipseStoreCacheConfigurationBuilder builder(Class keyType, Class valueType) {
+ return new EclipseStoreCacheConfigurationBuilder<>(keyType, valueType);
+ }
+
+ /**
+ * Create a CacheConfiguration builder initialized from the supplied helidon
+ * configuration node.
+ *
+ * @param type of the cache key
+ * @param type of the cache value
+ * @param config helidon configuration
+ * @param keyType type of the cache key
+ * @param valueType type of the cache value
+ * @return a new CacheConfiguration builder
+ */
+ public static EclipseStoreCacheConfigurationBuilder builder(Config config, Class keyType,
+ Class valueType) {
+ org.eclipse.serializer.configuration.types.Configuration.Builder configurationBuilder = Configuration.Builder();
+ if (config.exists()) {
+ config.detach().asMap().get().forEach(configurationBuilder::set);
+ }
+
+ Configuration configuration = configurationBuilder.buildConfiguration();
+ configuration.opt(KEY_TYPE).ifPresent((s) -> verifyType(s, keyType));
+ configuration.opt(VALUE_TYPE).ifPresent((s) -> verifyType(s, valueType));
+
+ return new EclipseStoreCacheConfigurationBuilder<>(configuration, keyType, valueType);
+ }
+
+ private static void verifyType(String typeName, Class> actualType) {
+ if (!typeName.equals(actualType.getTypeName())) {
+ throw new ConfigException("Eclipse Store cache-config type mismatch, expected value from configuration: " + typeName
+ + " but got: " + actualType.getTypeName());
+ }
+ }
+
+ @Override
+ public CacheConfiguration build() {
+ return cacheConfigBuilder.build();
+ }
+
+ @Override
+ public EclipseStoreCacheConfigurationBuilder readThrough(boolean readTrough) {
+ cacheConfigBuilder.readThrough(readTrough);
+ return this;
+ }
+
+ @Override
+ public EclipseStoreCacheConfigurationBuilder writeThrough(boolean writeThrough) {
+ cacheConfigBuilder.writeThrough(writeThrough);
+ return this;
+ }
+
+ @Override
+ public EclipseStoreCacheConfigurationBuilder storeByValue(boolean storeByValue) {
+ cacheConfigBuilder.storeByValue(storeByValue);
+ return this;
+ }
+
+ @Override
+ public EclipseStoreCacheConfigurationBuilder enableStatistics(boolean enableStatistics) {
+ cacheConfigBuilder.enableStatistics(enableStatistics);
+ return this;
+ }
+
+ @Override
+ public EclipseStoreCacheConfigurationBuilder enableManagement(boolean enableManagement) {
+ cacheConfigBuilder.enableManagement(enableManagement);
+ return this;
+ }
+
+ @Override
+ public EclipseStoreCacheConfigurationBuilder expiryPolicyFactory(Factory expiryPolicyFactory) {
+ cacheConfigBuilder.expiryPolicyFactory(expiryPolicyFactory);
+ return this;
+ }
+
+ @Override
+ public EclipseStoreCacheConfigurationBuilder evictionManagerFactory(
+ Factory> evictionManagerFactory) {
+ cacheConfigBuilder.evictionManagerFactory(evictionManagerFactory);
+ return this;
+ }
+
+ @Override
+ public EclipseStoreCacheConfigurationBuilder cacheLoaderFactory(
+ Factory> cacheLoaderFactory) {
+ cacheConfigBuilder.cacheLoaderFactory(cacheLoaderFactory);
+ return this;
+ }
+
+ @Override
+ public EclipseStoreCacheConfigurationBuilder cacheWriterFactory(
+ Factory> cacheWriterFactory) {
+ cacheConfigBuilder.cacheWriterFactory(cacheWriterFactory);
+ return this;
+ }
+
+ @Override
+ public Builder serializerFoundation(SerializerFoundation> serializerFoundation) {
+ return cacheConfigBuilder.serializerFoundation(serializerFoundation);
+ }
+
+ @Override
+ public Builder addListenerConfiguration(CacheEntryListenerConfiguration listenerConfiguration) {
+ cacheConfigBuilder.addListenerConfiguration(listenerConfiguration);
+ return this;
+ }
+}
diff --git a/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/package-info.java b/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/package-info.java
new file mode 100644
index 00000000000..d2caed57795
--- /dev/null
+++ b/integrations/eclipsestore/cache/src/main/java/io/helidon/integrations/eclipsestore/cache/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides support for Eclipse Store Cache features integration.
+ */
+package io.helidon.integrations.eclipsestore.cache;
diff --git a/integrations/eclipsestore/cache/src/main/java/module-info.java b/integrations/eclipsestore/cache/src/main/java/module-info.java
new file mode 100644
index 00000000000..300f1817a91
--- /dev/null
+++ b/integrations/eclipsestore/cache/src/main/java/module-info.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import io.helidon.common.features.api.Aot;
+import io.helidon.common.features.api.Feature;
+import io.helidon.common.features.api.HelidonFlavor;
+
+/**
+ * Provides support for EclipseStore Cache features integration.
+ */
+@SuppressWarnings({"requires-automatic", "requires-transitive-automatic"})
+@Feature(value = "Eclipse Store Cache",
+ description = "Eclipse Store Cache Integration",
+ in = HelidonFlavor.SE,
+ path = {"EclipseStore", "Cache"}
+)
+@Aot(false)
+module io.helidon.integrations.eclipsestore.cache {
+ requires transitive cache.api;
+ requires transitive io.helidon.integrations.eclipsestore;
+ requires transitive org.eclipse.store.cache;
+ requires transitive org.eclipse.serializer;
+
+ exports io.helidon.integrations.eclipsestore.cache;
+}
diff --git a/integrations/eclipsestore/cache/src/main/resources/META-INF/native-image/native-image.properties b/integrations/eclipsestore/cache/src/main/resources/META-INF/native-image/native-image.properties
new file mode 100644
index 00000000000..dcec89f6d9e
--- /dev/null
+++ b/integrations/eclipsestore/cache/src/main/resources/META-INF/native-image/native-image.properties
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+Args=--initialize-at-run-time=org.eclipse.store.cache.types.MBeanServerUtils
diff --git a/integrations/eclipsestore/cache/src/test/java/io/helidon/integrations/eclipsestore/cache/CacheTest.java b/integrations/eclipsestore/cache/src/test/java/io/helidon/integrations/eclipsestore/cache/CacheTest.java
new file mode 100644
index 00000000000..5e967ef76ef
--- /dev/null
+++ b/integrations/eclipsestore/cache/src/test/java/io/helidon/integrations/eclipsestore/cache/CacheTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cache;
+
+import io.helidon.config.ClasspathConfigSource;
+import io.helidon.config.Config;
+import io.helidon.config.ConfigSources;
+import org.eclipse.store.cache.types.Cache;
+import org.eclipse.store.cache.types.CacheConfiguration;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.nio.file.Path;
+import java.util.Map;
+
+class CacheTest {
+
+ @TempDir
+ Path tempDir;
+
+ @Test
+ void createCacheTest() {
+ CacheConfiguration config = EclipseStoreCacheConfigurationBuilder.builder(Integer.class, String.class)
+ .build();
+ CacheBuilder builder = CacheBuilder.builder(config, Integer.class, String.class);
+ Cache cache = builder.build("testCache");
+
+ cache.put(1, "Hello");
+
+ cache.close();
+ }
+
+ @Test
+ void createCacheFromConfigTest() {
+ Config helidonConfig = Config.builder().addSource(ClasspathConfigSource.create("/eclipsestoreCacheConfig.yml"))
+ .addSource(ConfigSources.create(Map.of("cache.eclipsestore.storage.storage-directory", tempDir.toString())))
+ .build();
+
+ CacheConfiguration config = EclipseStoreCacheConfigurationBuilder
+ .builder(helidonConfig.get("cache.eclipsestore"), Integer.class, String.class)
+ .build();
+
+ Cache cache = CacheBuilder.builder(config, Integer.class, String.class).build("Cache_IntStr");
+
+ cache.put(1, "Hello");
+
+ cache.close();
+ }
+}
diff --git a/integrations/eclipsestore/cache/src/test/java/io/helidon/integrations/eclipsestore/cache/ConfigurationTest.java b/integrations/eclipsestore/cache/src/test/java/io/helidon/integrations/eclipsestore/cache/ConfigurationTest.java
new file mode 100644
index 00000000000..6180d0d5ca6
--- /dev/null
+++ b/integrations/eclipsestore/cache/src/test/java/io/helidon/integrations/eclipsestore/cache/ConfigurationTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cache;
+
+import io.helidon.config.Config;
+import io.helidon.config.ConfigSources;
+import org.eclipse.store.cache.types.CacheConfiguration;
+import org.eclipse.store.cache.types.EvictionManager;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import javax.cache.configuration.Factory;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheWriter;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertAll;
+
+class ConfigurationTest {
+
+ /**
+ * Test if all default properties are set.
+ */
+ @Test
+ void defaultValuesTest() {
+ CacheConfiguration cacheConfig = EclipseStoreCacheConfigurationBuilder
+ .builder(Integer.class, String.class).build();
+
+ assertAll(() -> assertThat("getKeyType", cacheConfig.getKeyType(), typeCompatibleWith(Integer.class)),
+ () -> assertThat("getValueType", cacheConfig.getValueType(), typeCompatibleWith(String.class)),
+ () -> assertThat("isManagementEnabled", cacheConfig.isManagementEnabled(), is(false)),
+ () -> assertThat("isStatisticsEnabled", cacheConfig.isStatisticsEnabled(), is(false)),
+ () -> assertThat("isReadThrough", cacheConfig.isReadThrough(), is(false)),
+ () -> assertThat("isWriteThrough", cacheConfig.isWriteThrough(), is(false)),
+ () -> assertThat("isStoreByValue", cacheConfig.isStoreByValue(), is(false)),
+ () -> assertThat("getExpiryPolicyFactory", cacheConfig.getExpiryPolicyFactory(),
+ is(CacheConfiguration.DefaultExpiryPolicyFactory())),
+ () -> assertThat("getEvictionManagerFactory", cacheConfig.getEvictionManagerFactory(),
+ is(CacheConfiguration.DefaultEvictionManagerFactory())),
+ () -> assertThat("getCacheLoaderFactory", cacheConfig.getCacheLoaderFactory(), nullValue()),
+ () -> assertThat("getCacheWriterFactory", cacheConfig.getCacheWriterFactory(), nullValue()),
+ () -> assertThat("getCacheEntryListenerConfigurations",
+ cacheConfig.getCacheEntryListenerConfigurations(), emptyIterable()));
+ }
+
+ /**
+ * Test if simple configuration values are applied. This test does not check all
+ * values
+ */
+ @Test
+ void configValuesTest() {
+ Map source = Map.of("cache.management-enabled", "true", "cache.statistics-enabled", "true",
+ "cache.store-by-value", "true");
+
+ Config config = Config.builder().addSource(ConfigSources.create(source).build()).build();
+
+ CacheConfiguration cacheConfig = EclipseStoreCacheConfigurationBuilder
+ .builder(config.get("cache"), Long.class, String.class).build();
+
+ assertAll(() -> assertThat("getKeyType", cacheConfig.getKeyType(), typeCompatibleWith(Long.class)),
+ () -> assertThat("getValueType", cacheConfig.getValueType(), typeCompatibleWith(String.class)),
+ () -> assertThat("isManagementEnabled", cacheConfig.isManagementEnabled(), is(true)),
+ () -> assertThat("isStatisticsEnabled", cacheConfig.isStatisticsEnabled(), is(true)),
+ () -> assertThat("isStoreByValue", cacheConfig.isStoreByValue(), is(true)));
+ }
+
+ /**
+ * Test if settings from config can be altered by code
+ */
+ @Test
+ void applyChangeTest() {
+
+ Map source = Map.of("cache.management-enabled", "true", "cache.statistics-enabled", "true",
+ "cache.store-by-value", "true");
+
+ Config config = Config.builder().addSource(ConfigSources.create(source).build()).build();
+
+ CacheConfiguration cacheConfig = EclipseStoreCacheConfigurationBuilder
+ .builder(config.get("cache"), Long.class, String.class).disableManagement().storeByValue(false).build();
+
+ assertAll(() -> assertThat("isManagementEnabled", cacheConfig.isManagementEnabled(), is(false)),
+ () -> assertThat("isStatisticsEnabled", cacheConfig.isStatisticsEnabled(), is(true)),
+ () -> assertThat("isStoreByValue", cacheConfig.isStoreByValue(), is(false)));
+ }
+
+ @Test
+ void cacheLoaderFactoryTest() {
+ @SuppressWarnings("unchecked")
+ Factory> cacheLoaderFactory = Mockito.mock(Factory.class);
+
+ CacheConfiguration cacheConfig = EclipseStoreCacheConfigurationBuilder
+ .builder(Integer.class, String.class).cacheLoaderFactory(cacheLoaderFactory).build();
+
+ assertThat(cacheConfig.getCacheLoaderFactory(), sameInstance(cacheLoaderFactory));
+ }
+
+ @Test
+ void cacheWriterFactoryTest() {
+ @SuppressWarnings("unchecked")
+ Factory> cacheWriterFactory = Mockito.mock(Factory.class);
+
+ CacheConfiguration cacheConfig = EclipseStoreCacheConfigurationBuilder
+ .builder(Integer.class, String.class).cacheWriterFactory(cacheWriterFactory).build();
+
+ assertThat(cacheConfig.getCacheWriterFactory(), sameInstance(cacheWriterFactory));
+ }
+
+ @Test
+ void expiryPolicyFactoryTest() {
+ @SuppressWarnings("unchecked")
+ Factory expiryPolicyFactory = Mockito.mock(Factory.class);
+
+ CacheConfiguration cacheConfig = EclipseStoreCacheConfigurationBuilder
+ .builder(Integer.class, String.class).expiryPolicyFactory(expiryPolicyFactory).build();
+
+ assertThat(cacheConfig.getExpiryPolicyFactory(), sameInstance(expiryPolicyFactory));
+ }
+
+ @Test
+ void evictionManagerFactoryTest() {
+ @SuppressWarnings("unchecked")
+ Factory> evictionManagerFactory = Mockito.mock(Factory.class);
+
+ CacheConfiguration cacheConfig = EclipseStoreCacheConfigurationBuilder
+ .builder(Integer.class, String.class).evictionManagerFactory(evictionManagerFactory).build();
+
+ assertThat(cacheConfig.getEvictionManagerFactory(), sameInstance(evictionManagerFactory));
+ }
+
+}
diff --git a/integrations/eclipsestore/cache/src/test/resources/eclipsestoreCacheConfig.yml b/integrations/eclipsestore/cache/src/test/resources/eclipsestoreCacheConfig.yml
new file mode 100644
index 00000000000..abe7683c123
--- /dev/null
+++ b/integrations/eclipsestore/cache/src/test/resources/eclipsestoreCacheConfig.yml
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+cache:
+ eclipsestore:
+ missing_cache_strategy: create
+ readThrough: true
+ writeThrough: true
+ storage:
+ baseDirectory: ~/cache-data
+ channelCount: 4
diff --git a/integrations/eclipsestore/cdi/pom.xml b/integrations/eclipsestore/cdi/pom.xml
new file mode 100644
index 00000000000..035012d7484
--- /dev/null
+++ b/integrations/eclipsestore/cdi/pom.xml
@@ -0,0 +1,96 @@
+
+
+
+ 4.0.0
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore-project
+ 4.0.0-SNAPSHOT
+
+
+ helidon-integrations-eclipsestore-cdi
+ Helidon Integrations Eclipse Store CDI
+ jar
+
+ Eclipse Store JCache implementation
+
+
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore-cache
+
+
+ io.helidon.common.features
+ helidon-common-features-api
+ true
+
+
+ jakarta.annotation
+ jakarta.annotation-api
+ provided
+
+
+ jakarta.enterprise
+ jakarta.enterprise.cdi-api
+ provided
+
+
+
+ io.helidon.microprofile.cdi
+ helidon-microprofile-cdi
+ test
+
+
+ io.helidon.microprofile.testing
+ helidon-microprofile-testing-junit5
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ io.helidon.common.features
+ helidon-common-features-processor
+ ${helidon.version}
+
+
+
+
+
+
+
diff --git a/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/CacheExtension.java b/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/CacheExtension.java
new file mode 100644
index 00000000000..46b185bef0a
--- /dev/null
+++ b/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/CacheExtension.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cdi;
+
+
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+import io.helidon.common.GenericType;
+import io.helidon.config.Config;
+import io.helidon.integrations.eclipsestore.cache.CacheBuilder;
+
+import jakarta.annotation.Priority;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.event.Observes;
+import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
+import jakarta.enterprise.inject.spi.BeanManager;
+import jakarta.enterprise.inject.spi.Extension;
+import jakarta.enterprise.inject.spi.InjectionPoint;
+import jakarta.enterprise.inject.spi.ProcessInjectionPoint;
+import org.eclipse.store.cache.types.Cache;
+
+import static jakarta.interceptor.Interceptor.Priority.PLATFORM_BEFORE;
+
+/**
+ * An {@link Extension} that arranges for named {@link EclipseStoreCache}
+ * injection points to be satisfied.
+ */
+public class CacheExtension implements Extension {
+
+ private final Set cacheBeans;
+
+ private Config config;
+
+ /**
+ * Creates a new {@link CacheExtension}.
+ */
+ public CacheExtension() {
+ super();
+ cacheBeans = new HashSet<>();
+ }
+
+ private void configure(@Observes @Priority(PLATFORM_BEFORE) Config config) {
+ this.config = config;
+ }
+
+ /*
+ * Collect all injection points qualifiers for EclipseStore Cache
+ */
+ private > void processInjectionPoint(
+ @Observes final ProcessInjectionPoint, T> event) {
+ if (event != null) {
+ final InjectionPoint injectionPoint = event.getInjectionPoint();
+ if (injectionPoint != null) {
+ if (injectionPoint.getAnnotated().isAnnotationPresent(EclipseStoreCache.class)) {
+ this.cacheBeans.add(
+ new Descriptor(injectionPoint.getQualifiers(), (ParameterizedType) injectionPoint.getType()));
+ }
+ }
+ }
+ }
+
+ /*
+ * create EmbeddedStorageManager beans
+ */
+ private void addBeans(@Observes final AfterBeanDiscovery event, final BeanManager beanManager) {
+ if (event != null && beanManager != null) {
+ if (!this.cacheBeans.isEmpty()) {
+ for (final Descriptor entry : this.cacheBeans) {
+ assert entry != null;
+ // create Eclipse Store Cache bean
+ final Set qualifiers = entry.getAnnotations();
+ assert qualifiers != null;
+ assert !qualifiers.isEmpty();
+
+ ParameterizedType types = entry.getTypes();
+ GenericType> keyType = GenericType.create(types.getActualTypeArguments()[0]);
+ GenericType> valueType = GenericType.create(types.getActualTypeArguments()[1]);
+ String name = getName(qualifiers);
+
+ event.>addBean()
+ .qualifiers(qualifiers)
+ .scope(ApplicationScoped.class)
+ .addTransitiveTypeClosure(Cache.class)
+ .addTypes(types)
+ .createWith(cc -> CacheBuilder.create(name, getConfigNode(qualifiers), keyType.rawType(),
+ valueType.rawType()))
+ .destroyWith((cache, context) -> cache.close());
+ }
+ }
+ }
+ }
+
+ /*
+ * Get the config node that matches the name supplied by @EclipseStoreStorage
+ * annotation if no name is available the full helidon config is returned
+ */
+ private Config getConfigNode(Set qualifiers) {
+ Optional optAnnotation = qualifiers.stream().filter(e -> e instanceof EclipseStoreCache).findFirst();
+ if (optAnnotation.isPresent()) {
+ EclipseStoreCache annotation = (EclipseStoreCache) optAnnotation.get();
+ String name = annotation.configNode();
+ return config.get(name);
+ }
+ return null;
+ }
+
+ /*
+ * Get the name supplied by @EclipseStoreStorage
+ * annotation if no name is available null is returned
+ */
+ private String getName(Set qualifiers) {
+ Optional optAnnotation = qualifiers.stream().filter(e -> e instanceof EclipseStoreCache).findFirst();
+ if (optAnnotation.isPresent()) {
+ EclipseStoreCache annotation = (EclipseStoreCache) optAnnotation.get();
+ return annotation.name();
+ }
+ return null;
+ }
+
+ private static class Descriptor {
+
+ private final Set annotations;
+ private final ParameterizedType types;
+
+ private Descriptor(Set cacheBeans, ParameterizedType types) {
+ super();
+ this.annotations = cacheBeans;
+ this.types = types;
+ }
+
+ public Set getAnnotations() {
+ return annotations;
+ }
+
+ public ParameterizedType getTypes() {
+ return types;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(annotations, types);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Descriptor other = (Descriptor) obj;
+ return Objects.equals(annotations, other.annotations) && Objects.equals(types, other.types);
+ }
+ }
+}
diff --git a/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/EclipseStoreCache.java b/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/EclipseStoreCache.java
new file mode 100644
index 00000000000..b4653f66caa
--- /dev/null
+++ b/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/EclipseStoreCache.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cdi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import jakarta.inject.Qualifier;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+
+
+/**
+ * Creates a cache based upon the Eclipse Store JCache implementation.
+ *
See Eclipse Store JCache
+ *
+ * Specify the cache name by the name property.
+ *
+ * The configNode property expects an existing Helidon config node providing configuration properties for the cache.
+ *
See Eclipse Store JCache configuration
+ *
If not provided the properties below "org.eclipse.store.cache.default" will be used if existing.
+ * Otherwise the build in defaults are applied.
+ */
+@Qualifier
+@Retention(RUNTIME)
+@Target({PARAMETER, FIELD})
+public @interface EclipseStoreCache {
+ /**
+ * Specifies the configuration node used to configure the EmbeddedStorageManager instance to be created.
+ *
+ * @return the configuration node
+ */
+ String configNode() default "org.eclipse.store.cache.default";
+
+ /**
+ * Specifies the cache name.
+ *
+ * @return the cache name
+ */
+ String name();
+}
diff --git a/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/EclipseStoreStorage.java b/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/EclipseStoreStorage.java
new file mode 100644
index 00000000000..bcd356a42d9
--- /dev/null
+++ b/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/EclipseStoreStorage.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cdi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import jakarta.inject.Qualifier;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+
+
+/**
+ * Qualifier annotation for Eclise Store EmbeddedStorageManager.
+ */
+@Qualifier
+@Retention(RUNTIME)
+@Target({FIELD, PARAMETER})
+public @interface EclipseStoreStorage {
+ /**
+ * Specifies the configuration node used to configure the EmbeddedStorageManager instance to be created.
+ *
+ * @return the config node
+ */
+ String configNode();
+}
diff --git a/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/EmbeddedStorageManagerExtension.java b/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/EmbeddedStorageManagerExtension.java
new file mode 100644
index 00000000000..97f1a76038d
--- /dev/null
+++ b/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/EmbeddedStorageManagerExtension.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cdi;
+
+import java.lang.annotation.Annotation;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+
+import io.helidon.config.Config;
+import io.helidon.integrations.eclipsestore.core.EmbeddedStorageManagerBuilder;
+
+import jakarta.annotation.Priority;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.event.Observes;
+import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
+import jakarta.enterprise.inject.spi.BeanManager;
+import jakarta.enterprise.inject.spi.Extension;
+import jakarta.enterprise.inject.spi.InjectionPoint;
+import jakarta.enterprise.inject.spi.ProcessInjectionPoint;
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
+
+
+import static jakarta.interceptor.Interceptor.Priority.PLATFORM_BEFORE;
+
+/**
+ * An {@link Extension} that arranges for named {@link EclipseStoreStorage}
+ * injection points to be satisfied.
+ */
+public class EmbeddedStorageManagerExtension implements Extension {
+
+ private final Map, Object> embeddedStorageBeans;
+
+ private Config config;
+
+ /**
+ * Creates a new {@link EmbeddedStorageManagerExtension}.
+ */
+ public EmbeddedStorageManagerExtension() {
+ super();
+ embeddedStorageBeans = new HashMap<>();
+ }
+
+ private void configure(@Observes @Priority(PLATFORM_BEFORE) Config config) {
+ this.config = config;
+ }
+
+ /*
+ * Collect all injection points qualifiers for EmbeddedStorageManagers
+ */
+ private void processInjectionPoint(@Observes final ProcessInjectionPoint, T> event) {
+ if (event != null) {
+ final InjectionPoint injectionPoint = event.getInjectionPoint();
+ if (injectionPoint != null) {
+ this.embeddedStorageBeans.put(injectionPoint.getQualifiers(), null);
+ }
+ }
+ }
+
+ /*
+ * create EmbeddedStorageManager beans
+ */
+ private void addBeans(@Observes final AfterBeanDiscovery event, final BeanManager beanManager) {
+ if (event != null && beanManager != null) {
+ if (!this.embeddedStorageBeans.isEmpty()) {
+ for (final Entry, ?> entry : this.embeddedStorageBeans.entrySet()) {
+ assert entry != null;
+ if (entry.getValue() == null) {
+ // create EmbeddedStorageManager bean
+ final Set qualifiers = entry.getKey();
+ assert qualifiers != null;
+ assert !qualifiers.isEmpty();
+ event.addBean().scope(ApplicationScoped.class)
+ .addTransitiveTypeClosure(EmbeddedStorageManager.class)
+ .beanClass(EmbeddedStorageManager.class)
+ .qualifiers(qualifiers)
+ .createWith(cc -> EmbeddedStorageManagerBuilder.create(getConfigNode(qualifiers)).start())
+ .destroyWith((storageManager, context) -> storageManager.shutdown());
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Get the config node that matches the name supplied by @EclipseStoreStorage annotation
+ * if no name is available the full helidon config is returned
+ */
+ private Config getConfigNode(Set qualifiers) {
+ Optional optAnnotation = qualifiers
+ .stream()
+ .filter(e -> e instanceof EclipseStoreStorage)
+ .findFirst();
+ if (optAnnotation.isPresent()) {
+ EclipseStoreStorage value = (EclipseStoreStorage) optAnnotation.get();
+ String name = value.configNode();
+ return config.get(name);
+ }
+ return config;
+ }
+}
diff --git a/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/package-info.java b/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/package-info.java
new file mode 100644
index 00000000000..5fabc6cd6c4
--- /dev/null
+++ b/integrations/eclipsestore/cdi/src/main/java/io/helidon/integrations/eclipsestore/cdi/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides CDI support for Eclipse Store integration.
+ */
+package io.helidon.integrations.eclipsestore.cdi;
diff --git a/integrations/eclipsestore/cdi/src/main/java/module-info.java b/integrations/eclipsestore/cdi/src/main/java/module-info.java
new file mode 100644
index 00000000000..47c5dfc7057
--- /dev/null
+++ b/integrations/eclipsestore/cdi/src/main/java/module-info.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import io.helidon.common.features.api.Aot;
+import io.helidon.common.features.api.Feature;
+import io.helidon.common.features.api.HelidonFlavor;
+
+
+@Feature(value = "Eclipse Store",
+ description = "Eclipse Store Integration",
+ in = HelidonFlavor.MP,
+ path = {"EclipseStore", "CDI"}
+)
+@Aot(false)
+@SuppressWarnings({"requires-automatic", "requires-transitive-automatic"})
+module io.helidon.integrations.eclipsestore.cdi {
+ requires jakarta.annotation;
+ requires transitive cache.api;
+ requires transitive jakarta.cdi;
+ requires transitive jakarta.inject;
+
+ requires io.helidon.integrations.eclipsestore.cache;
+ exports io.helidon.integrations.eclipsestore.cdi;
+
+ provides jakarta.enterprise.inject.spi.Extension
+ with io.helidon.integrations.eclipsestore.cdi.EmbeddedStorageManagerExtension,
+ io.helidon.integrations.eclipsestore.cdi.CacheExtension;
+
+}
diff --git a/integrations/eclipsestore/cdi/src/test/java/io/helidon/integrations/eclipsestore/cdi/CacheManagerExtensionTest.java b/integrations/eclipsestore/cdi/src/test/java/io/helidon/integrations/eclipsestore/cdi/CacheManagerExtensionTest.java
new file mode 100644
index 00000000000..29de8bf21fc
--- /dev/null
+++ b/integrations/eclipsestore/cdi/src/test/java/io/helidon/integrations/eclipsestore/cdi/CacheManagerExtensionTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cdi;
+
+import io.helidon.integrations.eclipsestore.cache.ConfigException;
+import io.helidon.microprofile.testing.junit5.AddConfig;
+import io.helidon.microprofile.testing.junit5.HelidonTest;
+import jakarta.inject.Inject;
+import org.junit.jupiter.api.Test;
+
+import javax.cache.Cache;
+import java.time.Duration;
+import java.util.HashMap;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@HelidonTest
+@AddConfig(key = "org.eclipse.store.cache-HashMap.key-type", value = "java.lang.Integer")
+@AddConfig(key = "org.eclipse.store.cache-HashMap.value-type", value = "java.util.HashMap")
+@AddConfig(key = "org.eclipse.store.cache-wrongTypes.key-type", value = "java.lang.Integer")
+@AddConfig(key = "org.eclipse.store.cache-wrongTypes.value-type", value = "java.lang.String")
+class CacheManagerExtensionTest {
+
+ @Inject
+ @EclipseStoreCache(name = "intStrCache")
+ Cache cacheIntStr;
+
+ @Inject
+ @EclipseStoreCache(name = "intStrCache_2")
+ Cache cacheIntStr_2;
+
+ @Inject
+ @EclipseStoreCache(name = "intStrCache")
+ Cache cacheIntStr_3;
+
+ @Inject
+ @EclipseStoreCache(configNode = "org.eclipse.store.cache-wrongTypes", name = "wrongKeyType")
+ Cache cacheWrongKeyType;
+
+ @Inject
+ @EclipseStoreCache(configNode = "org.eclipse.store.cache-wrongTypes", name = "wrongValueType")
+ Cache cacheWrongValueType;
+
+ @Inject
+ @EclipseStoreCache(configNode = "org.eclipse.store.cache-HashMap", name = "cacheHashMap")
+ Cache> cacheHashMap;
+
+ @Test
+ void sameInstanceTest() {
+ assertThat(cacheIntStr, is(sameInstance(cacheIntStr_3)));
+ }
+
+ @Test
+ void differentInstancesTest() {
+ assertThat(cacheIntStr, is(not(sameInstance(cacheIntStr_2))));
+ }
+
+ @Test
+ void createTestWithoutConfigTest() {
+ cacheIntStr.put(1, "Hello");
+ assertThat(cacheIntStr.get(1), is("Hello"));
+ }
+
+ @Test
+ void wrongValueTypeTest() {
+ assertThrows(ConfigException.class, () -> cacheWrongValueType.put(1, 42));
+ }
+
+ @Test
+ void wrongKeyTypeTest() {
+ assertThrows(ConfigException.class, () -> cacheWrongKeyType.put("1", "Hello"));
+ }
+
+ @Test
+ void hashmapCacheTest() {
+ HashMap e1 = new HashMap<>();
+ e1.put("Duration_1", Duration.ofDays(2));
+ HashMap e2 = new HashMap<>();
+ e1.put("Duration_1", Duration.ofSeconds(2));
+ cacheHashMap.put(10, e1);
+ cacheHashMap.put(11, e2);
+ assertThat(cacheHashMap.get(10), sameInstance(e1));
+ assertThat(cacheHashMap.get(11), sameInstance(e2));
+ }
+
+}
diff --git a/integrations/eclipsestore/cdi/src/test/java/io/helidon/integrations/eclipsestore/cdi/EclipseStoreExtensionTest.java b/integrations/eclipsestore/cdi/src/test/java/io/helidon/integrations/eclipsestore/cdi/EclipseStoreExtensionTest.java
new file mode 100644
index 00000000000..acb47d19f9d
--- /dev/null
+++ b/integrations/eclipsestore/cdi/src/test/java/io/helidon/integrations/eclipsestore/cdi/EclipseStoreExtensionTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.cdi;
+
+import io.helidon.microprofile.testing.junit5.HelidonTest;
+import jakarta.inject.Inject;
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.nio.file.Path;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
+
+@HelidonTest
+class EclipseStoreExtensionTest {
+
+ @TempDir
+ static Path tempDir;
+
+ @Inject
+ @EclipseStoreStorage(configNode = "org.eclipse.store.storage.my_storage")
+ EmbeddedStorageManager storage;
+
+ @BeforeAll
+ static void beforeAll() {
+ System.setProperty("org.eclipse.store.storage.my_storage.storage-directory", tempDir.toString());
+ }
+
+ @AfterAll
+ static void afterAll() {
+ System.clearProperty("org.eclipse.store.storage.my_storage.storage-directory");
+ }
+
+ @Test
+ void testInjectedInstances() {
+ assertThat(storage, notNullValue());
+ assertThat(storage.isRunning(), equalTo(true));
+ }
+
+}
diff --git a/integrations/eclipsestore/cdi/src/test/resources/META-INF/microprofile-config.properties b/integrations/eclipsestore/cdi/src/test/resources/META-INF/microprofile-config.properties
new file mode 100644
index 00000000000..a6fc62ff468
--- /dev/null
+++ b/integrations/eclipsestore/cdi/src/test/resources/META-INF/microprofile-config.properties
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2019, 2024 Oracle and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+org.eclipse.store.storage.my_storage.channel-count=4
+org.eclipse.store.storage.my_storage.housekeeping-interval=2000ms
diff --git a/integrations/eclipsestore/core/pom.xml b/integrations/eclipsestore/core/pom.xml
new file mode 100644
index 00000000000..3589d5f1fa8
--- /dev/null
+++ b/integrations/eclipsestore/core/pom.xml
@@ -0,0 +1,90 @@
+
+
+
+ 4.0.0
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore-project
+ 4.0.0-SNAPSHOT
+
+
+ helidon-integrations-eclipsestore
+ Helidon Integrations Eclipse Store
+ jar
+
+
+
+ org.eclipse.store
+ storage-embedded
+
+
+ org.eclipse.store
+ storage-embedded-configuration
+
+
+ org.eclipse.serializer
+ persistence-binary-jdk17
+
+
+ io.helidon.config
+ helidon-config
+
+
+ io.helidon.common.features
+ helidon-common-features-api
+ true
+
+
+ io.helidon.config
+ helidon-config-yaml
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ io.helidon.common.features
+ helidon-common-features-processor
+ ${helidon.version}
+
+
+
+
+
+
+
diff --git a/integrations/eclipsestore/core/src/main/java/io/helidon/integrations/eclipsestore/core/EmbeddedStorageManagerBuilder.java b/integrations/eclipsestore/core/src/main/java/io/helidon/integrations/eclipsestore/core/EmbeddedStorageManagerBuilder.java
new file mode 100644
index 00000000000..7a11486f29b
--- /dev/null
+++ b/integrations/eclipsestore/core/src/main/java/io/helidon/integrations/eclipsestore/core/EmbeddedStorageManagerBuilder.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.core;
+
+import java.time.Duration;
+import java.util.Map;
+
+import io.helidon.config.Config;
+
+import org.eclipse.serializer.configuration.types.ByteSize;
+import org.eclipse.serializer.persistence.binary.jdk17.types.BinaryHandlersJDK17;
+import org.eclipse.store.storage.embedded.configuration.types.EmbeddedStorageConfigurationBuilder;
+import org.eclipse.store.storage.embedded.configuration.types.EmbeddedStorageFoundationCreatorConfigurationBased;
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
+import org.eclipse.store.storage.types.StorageEntityCacheEvaluator;
+
+
+
+/**
+ * Builder for Eclipse Store EmbeddedStorageManager.
+ */
+public class EmbeddedStorageManagerBuilder implements io.helidon.common.Builder {
+ private final EmbeddedStorageConfigurationBuilder configurationBuilder;
+
+ private EmbeddedStorageManagerBuilder() {
+ super();
+ configurationBuilder = EmbeddedStorageConfigurationBuilder.New();
+ }
+
+ /**
+ * A builder for the EmbeddedStorageManager.
+ *
+ * @return a new fluent API builder
+ */
+ public static EmbeddedStorageManagerBuilder builder() {
+ return new EmbeddedStorageManagerBuilder();
+ }
+
+ /**
+ * Create a EmbeddedStorageManager instance from Config.
+ *
+ * @param config configuration to use
+ * @return new EmbeddedStorageManager instance
+ */
+ public static EmbeddedStorageManager create(Config config) {
+ return builder().config(config).build();
+ }
+
+ @Override
+ public EmbeddedStorageManager build() {
+ var embeddedStorageFoundation = EmbeddedStorageFoundationCreatorConfigurationBased
+ .New(configurationBuilder
+ .buildConfiguration())
+ .createEmbeddedStorageFoundation();
+ embeddedStorageFoundation.onConnectionFoundation(BinaryHandlersJDK17::registerJDK17TypeHandlers);
+ return embeddedStorageFoundation.createEmbeddedStorageManager();
+ }
+
+ /**
+ * Update builder from configuration.
+ *
+ * @param config
+ * @return the fluent API builder
+ */
+ public EmbeddedStorageManagerBuilder config(Config config) {
+ Map configMap = config.detach().asMap().get();
+
+ configMap.forEach(configurationBuilder::set);
+
+ return this;
+ }
+
+ /**
+ * The base directory of the storage in the file system.
+ *
+ * @param storageDirectory location of the storage as string.
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder storageDirectory(String storageDirectory) {
+ configurationBuilder.setStorageDirectory(storageDirectory);
+ return this;
+ }
+
+ /**
+ * The backup directory.
+ *
+ * @param backupDirectory location of the storage backup as string.
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder backupDirectory(String backupDirectory) {
+ configurationBuilder.setBackupDirectory(backupDirectory);
+ return this;
+ }
+
+ /**
+ * The deletion directory.
+ *
+ * @param deletionDirectory location of the storage's deleted files backup as string.
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder deletionDirectory(String deletionDirectory) {
+ configurationBuilder.setDeletionDirectory(deletionDirectory);
+ return this;
+ }
+
+ /**
+ * The truncation directory.
+ *
+ * @param truncationDirectory location of the storage's truncation files backup as string.
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder truncationDirectory(String truncationDirectory) {
+ configurationBuilder.setDeletionDirectory(truncationDirectory);
+ return this;
+ }
+
+ /**
+ * Name prefix of the subdirectories used by the channel threads. Default is
+ * "channel_".
+ *
+ * @param channelDirectoryPrefix new prefix
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder channelDirectoryPrefix(String channelDirectoryPrefix) {
+ configurationBuilder.setChannelDirectoryPrefix(channelDirectoryPrefix);
+ return this;
+ }
+
+ /**
+ * Name prefix of the storage files. Default is "channel_".
+ *
+ * @param dataFilePrefix new prefix
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder dataFilePrefix(String dataFilePrefix) {
+ configurationBuilder.setDataFilePrefix(dataFilePrefix);
+ return this;
+ }
+
+ /**
+ * Name suffix of the storage files. Default is ".dat".
+ *
+ * @param dataFileSuffix new suffix
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder dataFileSuffix(String dataFileSuffix) {
+ configurationBuilder.setDataFileSuffix(dataFileSuffix);
+ return this;
+ }
+
+ /**
+ * Name prefix of the storage transaction file. Default is
+ * "transactions_".
+ *
+ * @param transactionFilePrefix new prefix
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder transactionFilePrefix(String transactionFilePrefix) {
+ configurationBuilder.setTransactionFilePrefix(transactionFilePrefix);
+ return this;
+ }
+
+ /**
+ * Name suffix of the storage transaction file. Default is ".sft".
+ *
+ * @param transactionFileSuffix new suffix
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder transactionFileSuffix(String transactionFileSuffix) {
+ configurationBuilder.setTransactionFileSuffix(transactionFileSuffix);
+ return this;
+ }
+
+ /**
+ * The name of the dictionary file. Default is
+ * "PersistenceTypeDictionary.ptd".
+ *
+ * @param typeDictionaryFilename new name
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder typeDictionaryFilename(String typeDictionaryFilename) {
+ configurationBuilder.setTypeDictionaryFileName(typeDictionaryFilename);
+ return this;
+ }
+
+ /**
+ * Name suffix of the storage rescue files. Default is ".bak".
+ *
+ * @param rescuedFileSuffix
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder rescuedFileSuffix(String rescuedFileSuffix) {
+ configurationBuilder.setRescuedFileSuffix(rescuedFileSuffix);
+ return this;
+ }
+
+ /**
+ * Name of the lock file. Default is "used.lock"
+ *
+ * @param lockFileName
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder lockFileName(String lockFileName) {
+ configurationBuilder.setLockFileName(lockFileName);
+ return this;
+ }
+
+ /**
+ * The number of threads and number of directories used by the storage engine.
+ * Every thread has exclusive access to its directory. Default is
+ * 1.
+ *
+ * @param channelCount the new channel count, must be a power of 2
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder channelCount(int channelCount) {
+ configurationBuilder.setChannelCount(channelCount);
+ return this;
+ }
+
+ /**
+ * Interval in milliseconds for the housekeeping. This is work like garbage
+ * collection or cache checking. In combination with
+ * {@link #housekeepingTimeBudget(Duration)} the maximum processor time for
+ * housekeeping work can be set. Default is 1000 (every second).
+ *
+ * @param housekeepingInterval the new interval
+ * @return EmbeddedStorageManager builder
+ * @see #housekeepingTimeBudget(Duration)
+ */
+ public EmbeddedStorageManagerBuilder housekeepingInterval(Duration housekeepingInterval) {
+ configurationBuilder.setHousekeepingInterval(housekeepingInterval);
+ return this;
+ }
+
+ /**
+ * Number of nanoseconds used for each housekeeping cycle. However, no matter
+ * how low the number is, one item of work will always be completed. But if
+ * there is nothing to clean up, no processor time will be wasted. Default is
+ * 10000000 (10 million nanoseconds = 10 milliseconds = 0.01
+ * seconds).
+ *
+ * @param housekeepingTimeBudget the new time budget
+ * @return EmbeddedStorageManager builder
+ * @see #housekeepingInterval(Duration)
+ */
+ public EmbeddedStorageManagerBuilder housekeepingTimeBudget(Duration housekeepingTimeBudget) {
+ configurationBuilder.setHousekeepingTimeBudget(housekeepingTimeBudget);
+ return this;
+ }
+
+ /**
+ * Timeout in milliseconds for the entity cache evaluator. If an entity wasn't
+ * accessed in this timespan it will be removed from the cache. Default is
+ * 86400000 (1 day).
+ *
+ * @param entityCacheTimeout
+ * @return EmbeddedStorageManager builder
+ * @see Duration
+ */
+ public EmbeddedStorageManagerBuilder entityCacheTimeout(Duration entityCacheTimeout) {
+ configurationBuilder.setEntityCacheTimeout(entityCacheTimeout);
+ return this;
+ }
+
+ /**
+ * Abstract threshold value for the lifetime of entities in the cache. See
+ * {@link StorageEntityCacheEvaluator}. Default is 1000000000.
+ *
+ * @param entityCacheThreshold the new threshold
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder entityCacheThreshold(long entityCacheThreshold) {
+ configurationBuilder.setEntityCacheThreshold(entityCacheThreshold);
+ return this;
+ }
+
+ /**
+ * Minimum file size for a data file to avoid cleaning it up. Default is 1024^2
+ * = 1 MiB.
+ *
+ * @param dataFileMinimumSize the new minimum file size
+ * @return EmbeddedStorageManager builder
+ * @see #dataFileMinimumUseRatio(double)
+ */
+ public EmbeddedStorageManagerBuilder dataFileMinimumSize(ByteSize dataFileMinimumSize) {
+ configurationBuilder.setDataFileMinimumSize(dataFileMinimumSize);
+ return this;
+ }
+
+ /**
+ * Maximum file size for a data file to avoid cleaning it up. Default is
+ * 1024^2*8 = 8 MiB.
+ *
+ * @param dataFileMaximumSize the new maximum file size
+ * @return EmbeddedStorageManager builder
+ * @see #dataFileMinimumUseRatio(double)
+ */
+ public EmbeddedStorageManagerBuilder dataFileMaximumSize(ByteSize dataFileMaximumSize) {
+ configurationBuilder.setDataFileMaximumSize(dataFileMaximumSize);
+ return this;
+ }
+
+ /**
+ * The ratio (value in ]0.0;1.0]) of non-gap data contained in a storage file to
+ * prevent the file from being dissolved. "Gap" data is anything that is not the
+ * latest version of an entity's data, including older versions of an entity and
+ * "comment" bytes (a sequence of bytes beginning with its length as a negative
+ * value length header).
+ * The closer this value is to 1.0 (100%), the less disk space is occupied by
+ * storage files, but the more file dissolving (data transfers to new files) is
+ * required and vice versa.
+ *
+ * @param dataFileMinimumUseRatio the new minimum use ratio
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder dataFileMinimumUseRatio(double dataFileMinimumUseRatio) {
+ configurationBuilder.setDataFileMinimumUseRatio(dataFileMinimumUseRatio);
+ return this;
+ }
+
+ /**
+ * A flag defining whether the current head file (the only file actively written
+ * to) shall be subjected to file cleanups as well.
+ *
+ * @param dataFileCleanupHeadFile
+ * @return EmbeddedStorageManager builder
+ */
+ public EmbeddedStorageManagerBuilder dataFileCleanupHeadFile(boolean dataFileCleanupHeadFile) {
+ configurationBuilder.setDataFileCleanupHeadFile(dataFileCleanupHeadFile);
+ return this;
+ }
+
+}
diff --git a/integrations/eclipsestore/core/src/main/java/io/helidon/integrations/eclipsestore/core/package-info.java b/integrations/eclipsestore/core/src/main/java/io/helidon/integrations/eclipsestore/core/package-info.java
new file mode 100644
index 00000000000..06057aabe81
--- /dev/null
+++ b/integrations/eclipsestore/core/src/main/java/io/helidon/integrations/eclipsestore/core/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides support for Eclipse Store core features integration.
+ */
+package io.helidon.integrations.eclipsestore.core;
diff --git a/integrations/eclipsestore/core/src/main/java/module-info.java b/integrations/eclipsestore/core/src/main/java/module-info.java
new file mode 100644
index 00000000000..db7f15cfda0
--- /dev/null
+++ b/integrations/eclipsestore/core/src/main/java/module-info.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import io.helidon.common.features.api.Aot;
+import io.helidon.common.features.api.Feature;
+import io.helidon.common.features.api.HelidonFlavor;
+
+/**
+ * Provides support for Eclipse Store core features integration.
+ */
+@Feature(value = "Eclipse Store",
+ description = "Eclipse Store Integration",
+ in = HelidonFlavor.SE,
+ path = "EclipseStore")
+@Aot(false)
+module io.helidon.integrations.eclipsestore {
+ requires transitive static io.helidon.common.features.api;
+ requires transitive io.helidon.config;
+ requires transitive io.helidon.common;
+
+ requires transitive org.eclipse.store.storage.embedded.configuration;
+ requires transitive org.eclipse.serializer.persistence.binary.jdk17;
+
+ exports io.helidon.integrations.eclipsestore.core;
+}
diff --git a/integrations/eclipsestore/core/src/main/resources/META-INF/native-image/reflect-config.json b/integrations/eclipsestore/core/src/main/resources/META-INF/native-image/reflect-config.json
new file mode 100644
index 00000000000..b0e2808cf58
--- /dev/null
+++ b/integrations/eclipsestore/core/src/main/resources/META-INF/native-image/reflect-config.json
@@ -0,0 +1,548 @@
+[
+ {
+ "name": "org.eclipse.store.afs.nio.types.NioReadableFile$Default[]"
+ },
+ {
+ "name": "org.eclipse.store.memory.sun.JdkInternals$ObjectHeaderSizeDummy",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true,
+ "fields": [
+ {
+ "name": "calculateByteSizeObjectHeaderFieldOffsetDummy",
+ "allowUnsafeAccess": true
+ }
+ ]
+ },
+ {
+ "name": "java.net.URL",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "boolean",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "byte",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "char",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "double",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "float",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "int",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.io.File",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Boolean",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Byte",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Character",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Class",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Double",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Float",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Integer",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Long",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Object",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Object[]",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.Short",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.String",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.StringBuffer",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.StringBuilder",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.String[]"
+ },
+ {
+ "name": "java.lang.Void",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.ref.WeakReference[]"
+ },
+ {
+ "name": "java.lang.reflect.Field[]"
+ },
+ {
+ "name": "java.math.BigDecimal",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.math.BigInteger",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.net.Inet4Address",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.net.Inet6Address",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.net.InetAddress",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.net.InetSocketAddress",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.net.URI",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.net.URL",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.nio.file.OpenOption[]"
+ },
+ {
+ "name": "java.nio.file.Path",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.sql.Date",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.sql.Time",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.sql.Timestamp",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.AbstractCollection",
+ "allDeclaredFields": true
+ },
+ {
+ "name": "java.util.AbstractList",
+ "allDeclaredFields": true
+ },
+ {
+ "name": "java.util.AbstractMap",
+ "allDeclaredFields": true
+ },
+ {
+ "name": "java.util.AbstractSet",
+ "allDeclaredFields": true
+ },
+ {
+ "name": "java.util.ArrayDeque",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.ArrayList",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Collections$EmptyList",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Collections$EmptyMap",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Collections$EmptySet",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Collections$ReverseComparator",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Collections$UnmodifiableNavigableMap$EmptyNavigableMap",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Collections$UnmodifiableNavigableSet$EmptyNavigableSet",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Comparator"
+ },
+ {
+ "name": "java.util.Comparators$NaturalOrderComparator",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Currency",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Date",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.HashMap",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.HashSet",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Hashtable",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.IdentityHashMap",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.LinkedHashMap",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.LinkedHashSet",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.LinkedList",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.List",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Locale",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Optional",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true,
+ "fields": [
+ {
+ "name": "value",
+ "allowWrite": true
+ }
+ ]
+ },
+ {
+ "name": "java.util.OptionalDouble",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.OptionalInt",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.OptionalLong",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.PriorityQueue",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Properties",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Stack",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.TreeMap",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.TreeSet",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.Vector",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.WeakHashMap",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.concurrent.ConcurrentHashMap",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.concurrent.ConcurrentLinkedDeque",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.concurrent.ConcurrentLinkedQueue",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.concurrent.ConcurrentSkipListMap",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.concurrent.ConcurrentSkipListSet",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.concurrent.CopyOnWriteArrayList",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "java.util.regex.Pattern",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "long",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store..collections.BulkList",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.ConstHashEnum",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.ConstHashTable",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.ConstHashTable$Keys"
+ },
+ {
+ "name": "org.eclipse.store.collections.ConstHashTable$Values"
+ },
+ {
+ "name": "org.eclipse.store.collections.ConstList",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.Empty",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.EmptyTable",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true,
+ "fields": [
+ {
+ "name": "keys",
+ "allowWrite": true
+ },
+ {
+ "name": "values",
+ "allowWrite": true
+ }
+ ]
+ },
+ {
+ "name": "org.eclipse.store.collections.EmptyTable$Keys",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true,
+ "fields": [
+ {
+ "name": "this$0",
+ "allowWrite": true
+ }
+ ]
+ },
+ {
+ "name": "org.eclipse.store.collections.EmptyTable$Values",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true,
+ "fields": [
+ {
+ "name": "this$0",
+ "allowWrite": true
+ }
+ ]
+ },
+ {
+ "name": "org.eclipse.store.collections.EqBulkList",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.EqConstHashEnum",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.EqConstHashTable",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.EqConstHashTable$Keys"
+ },
+ {
+ "name": "org.eclipse.store.collections.EqConstHashTable$Values"
+ },
+ {
+ "name": "org.eclipse.store.collections.EqHashEnum",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.EqHashTable",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.EqHashTable$Keys"
+ },
+ {
+ "name": "org.eclipse.store.collections.EqHashTable$Values"
+ },
+ {
+ "name": "org.eclipse.store.collections.FixedList",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.HashEnum",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.HashTable",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.HashTable$Keys"
+ },
+ {
+ "name": "org.eclipse.store.collections.HashTable$Values"
+ },
+ {
+ "name": "org.eclipse.store.collections.LimitList",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.collections.Singleton",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.hashing.HashEqualator"
+ },
+ {
+ "name": "org.eclipse.store.hashing.XHashing$SingletonIdentityHashEqualator",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.hashing.XHashing$SingletonKeyValueIdentityHashEqualator",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.hashing.XHashing$SingletonValueHashEqualator",
+ "allDeclaredFields": true,
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.persistence.binary.java.net.BinaryHandlerInetSocketAddress",
+ "allDeclaredFields": true
+ },
+ {
+ "name": "org.eclipse.store.persistence.binary.types.BinaryField[]"
+ },
+ {
+ "name": "org.eclipse.store.persistence.binary.types.BinaryReferenceTraverser[]"
+ },
+ {
+ "name": "org.eclipse.store.persistence.binary.types.LoadItemsChain$Entry[]"
+ },
+ {
+ "name": "org.eclipse.store.persistence.types.PersistenceRootReference$Default",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.persistence.types.PersistenceRoots$Default",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.persistence.types.PersistenceTypeDefinitionMemberFieldGeneric[]"
+ },
+ {
+ "name": "org.eclipse.store.persistence.types.PersistenceTypeDescription[]"
+ },
+ {
+ "name": "org.eclipse.store.reference.Lazy$Default",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "org.eclipse.store.util.Substituter$Default",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "short",
+ "allDeclaredMethods": true
+ },
+ {
+ "name": "sun.misc.Unsafe",
+ "fields": [
+ {
+ "name": "theUnsafe"
+ }
+ ]
+ }
+]
diff --git a/integrations/eclipsestore/core/src/test/java/io/helidon/integrations/eclipsestore/core/ConfigurationTest.java b/integrations/eclipsestore/core/src/test/java/io/helidon/integrations/eclipsestore/core/ConfigurationTest.java
new file mode 100644
index 00000000000..68eede4767d
--- /dev/null
+++ b/integrations/eclipsestore/core/src/test/java/io/helidon/integrations/eclipsestore/core/ConfigurationTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.core;
+
+import io.helidon.config.ClasspathConfigSource;
+import io.helidon.config.Config;
+import io.helidon.config.ConfigSources;
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.text.StringContainsInOrder.stringContainsInOrder;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class ConfigurationTest {
+
+ @TempDir
+ Path tempDir;
+
+ @Test
+ void createFromConfigTest() {
+
+ Config helidonConfig = Config.builder().addSource(ClasspathConfigSource.create("/eclipsestoreConfig.yml"))
+ .addSource(ConfigSources.create(Map.of("eclipsestore.storage-directory", tempDir.toString())))
+ .build();
+
+ EmbeddedStorageManagerBuilder embeddedStorageManagerBuilder = EmbeddedStorageManagerBuilder.builder();
+ EmbeddedStorageManager embeddedStorageManager = embeddedStorageManagerBuilder.config(helidonConfig.get("eclipsestore"))
+ .build();
+
+ assertNotNull(embeddedStorageManager, "embeddedStorageManager is null!");
+
+ //need to compare strings as the eclipse store Path is not a java path
+ assertThat(tempDir.toString(), stringContainsInOrder(
+ Arrays.asList(embeddedStorageManager.configuration().fileProvider().baseDirectory().toPath())));
+
+ assertThat(embeddedStorageManager.configuration().channelCountProvider().getChannelCount(), is(4));
+ assertThat(embeddedStorageManager.configuration().housekeepingController().housekeepingIntervalMs(), is(2000L));
+ }
+}
diff --git a/integrations/eclipsestore/core/src/test/resources/eclipsestoreConfig.yml b/integrations/eclipsestore/core/src/test/resources/eclipsestoreConfig.yml
new file mode 100644
index 00000000000..c4b6be3caa9
--- /dev/null
+++ b/integrations/eclipsestore/core/src/test/resources/eclipsestoreConfig.yml
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2021, 2024 Oracle and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+openapi:
+ web-context: /otheropenapi
+ port: 0
+
+eclipsestore:
+ channel-count: 4
+ housekeeping-interval: 2000ms
diff --git a/integrations/eclipsestore/health/pom.xml b/integrations/eclipsestore/health/pom.xml
new file mode 100644
index 00000000000..04c939ab538
--- /dev/null
+++ b/integrations/eclipsestore/health/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+ 4.0.0
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore-project
+ 4.0.0-SNAPSHOT
+
+
+ helidon-integrations-eclipsestore-health
+ Helidon Integrations Eclipse Store Health
+
+ Health check for Eclipse Store
+
+
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore
+
+
+ io.helidon.webserver.observe
+ helidon-webserver-observe-health
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+
diff --git a/integrations/eclipsestore/health/src/main/java/io/helidon/integrations/eclipsestore/health/EclipseStoreHealthCheck.java b/integrations/eclipsestore/health/src/main/java/io/helidon/integrations/eclipsestore/health/EclipseStoreHealthCheck.java
new file mode 100644
index 00000000000..670d7af0be1
--- /dev/null
+++ b/integrations/eclipsestore/health/src/main/java/io/helidon/integrations/eclipsestore/health/EclipseStoreHealthCheck.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.health;
+
+import java.time.Duration;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import io.helidon.health.HealthCheck;
+import io.helidon.health.HealthCheckResponse;
+
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
+
+
+/**
+ * Eclipse Store health check.
+ */
+public class EclipseStoreHealthCheck implements HealthCheck {
+
+ private static final String DEFAULT_NAME = "EclipseStore";
+ private static final long DEFAULT_TIMEOUT_SECONDS = 10;
+
+ private final EmbeddedStorageManager embeddedStorageManager;
+ private final long timeoutDuration;
+ private final TimeUnit timeoutUnit;
+ private final String name;
+
+ private EclipseStoreHealthCheck(Builder builder) {
+ this.embeddedStorageManager = builder.embeddedStorageManager;
+ this.timeoutDuration = builder.timeoutDuration;
+ this.timeoutUnit = builder.timeoutUnit;
+ this.name = builder.name;
+ }
+
+ /**
+ * Create a default health check for Eclipse Store.
+ *
+ * @param embeddedStorageManager the EmbeddedStorageManager used by the the health check
+ * @return default health check for Eclipse Store.
+ */
+ public static EclipseStoreHealthCheck create(EmbeddedStorageManager embeddedStorageManager) {
+ return builder(embeddedStorageManager).build();
+ }
+
+ /**
+ * A fluent API builder to create a health check for Eclipse Store.
+ *
+ * @param embeddedStorageManager EmbeddedStorageManager
+ * @return a new builder
+ */
+ public static Builder builder(EmbeddedStorageManager embeddedStorageManager) {
+ return new Builder(embeddedStorageManager);
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public HealthCheckResponse call() {
+ HealthCheckResponse.Builder builder = HealthCheckResponse.builder();
+
+ try {
+ CompletableFuture status = CompletableFuture.supplyAsync(embeddedStorageManager::isRunning)
+ .orTimeout(timeoutDuration, timeoutUnit);
+
+ builder.status(status.get());
+ } catch (Throwable e) {
+ builder.status(false)
+ .detail("ErrorMessage", e.getMessage())
+ .detail("ErrorClass", e.getClass().getName());
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Builder for EclipseStoreHealthCheck.
+ */
+ public static class Builder implements io.helidon.common.Builder {
+
+ private final EmbeddedStorageManager embeddedStorageManager;
+
+ private long timeoutDuration;
+ private TimeUnit timeoutUnit;
+ private String name;
+
+ private Builder(EmbeddedStorageManager embeddedStorageManager) {
+ this.embeddedStorageManager = embeddedStorageManager;
+ this.name = DEFAULT_NAME;
+ this.timeoutDuration = DEFAULT_TIMEOUT_SECONDS;
+ this.timeoutUnit = TimeUnit.SECONDS;
+ }
+
+ @Override
+ public EclipseStoreHealthCheck build() {
+ return new EclipseStoreHealthCheck(this);
+ }
+
+ /**
+ * Customized name of the health check.
+ *
+ * @param name name of the health check
+ * @return updated builder instance
+ */
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Set custom timeout to wait for statement execution response. Default value is
+ * 10 seconds.
+ *
+ * @param duration the maximum time to wait for statement execution response
+ * @param timeUnit the time unit of the timeout argument
+ * @return updated builder instance
+ * @deprecated use {@link #timeout(Duration)} instead
+ */
+ @Deprecated(since = "4.0.0", forRemoval = true)
+ public Builder timeout(long duration, TimeUnit timeUnit) {
+ this.timeoutDuration = duration;
+ this.timeoutUnit = timeUnit;
+ return this;
+ }
+
+ /**
+ * Set custom timeout to wait for statement execution response. Default value is
+ * 10 seconds.
+ *
+ * @param duration the maximum time to wait for statement execution response
+ * @return updated builder instance
+ */
+ public Builder timeout(Duration duration) {
+ this.timeoutDuration = duration.toNanos();
+ this.timeoutUnit = TimeUnit.NANOSECONDS;
+ return this;
+ }
+ }
+}
diff --git a/integrations/eclipsestore/health/src/main/java/io/helidon/integrations/eclipsestore/health/package-info.java b/integrations/eclipsestore/health/src/main/java/io/helidon/integrations/eclipsestore/health/package-info.java
new file mode 100644
index 00000000000..051295f1fc0
--- /dev/null
+++ b/integrations/eclipsestore/health/src/main/java/io/helidon/integrations/eclipsestore/health/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides support for Eclipse store HealthChecks features integration.
+ */
+package io.helidon.integrations.eclipsestore.health;
diff --git a/integrations/eclipsestore/health/src/main/java/module-info.java b/integrations/eclipsestore/health/src/main/java/module-info.java
new file mode 100644
index 00000000000..0325c979d91
--- /dev/null
+++ b/integrations/eclipsestore/health/src/main/java/module-info.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import io.helidon.common.features.api.Aot;
+import io.helidon.common.features.api.Feature;
+import io.helidon.common.features.api.HelidonFlavor;
+
+/**
+ * Provides support for MEclipse Store HealthChecks features integration.
+ */
+@Feature(value = "Eclipse Store Health",
+ description = "Eclipse Store Health Integration",
+ in = HelidonFlavor.SE,
+ path = {"EclipseStore", "Health"}
+)
+@Aot(false)
+module io.helidon.integrations.eclipsestore.health {
+ requires transitive io.helidon.health;
+ requires transitive io.helidon.integrations.eclipsestore;
+
+ exports io.helidon.integrations.eclipsestore.health;
+
+}
diff --git a/integrations/eclipsestore/health/src/test/java/io/helidon/integrations/eclipsestore/health/EclipseStoreHealthTest.java b/integrations/eclipsestore/health/src/test/java/io/helidon/integrations/eclipsestore/health/EclipseStoreHealthTest.java
new file mode 100644
index 00000000000..661da9432b9
--- /dev/null
+++ b/integrations/eclipsestore/health/src/test/java/io/helidon/integrations/eclipsestore/health/EclipseStoreHealthTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.health;
+
+import io.helidon.health.HealthCheckResponse;
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+class EclipseStoreHealthTest {
+ private EmbeddedStorageManager embeddedStorageManager;
+
+ @BeforeEach
+ void init() {
+ embeddedStorageManager = Mockito.mock(EmbeddedStorageManager.class);
+ }
+
+ private void setEclipseStoreStatus(boolean isRunning) {
+ Mockito.when(embeddedStorageManager.isRunning()).thenReturn(isRunning);
+ }
+
+ @Test
+ void testStatusRunning() {
+ setEclipseStoreStatus(true);
+ EclipseStoreHealthCheck check = EclipseStoreHealthCheck.create(embeddedStorageManager);
+ HealthCheckResponse response = check.call();
+ assertThat(response.status(), is(HealthCheckResponse.Status.UP));
+ }
+
+ @Test
+ void testStatusNotRunning() {
+ setEclipseStoreStatus(false);
+ EclipseStoreHealthCheck check = EclipseStoreHealthCheck.create(embeddedStorageManager);
+ HealthCheckResponse response = check.call();
+ assertThat(response.status(), is(HealthCheckResponse.Status.DOWN));
+ }
+
+ @Test
+ void testStatusTimeout() {
+
+ Mockito.when(embeddedStorageManager.isRunning()).then((x) -> {
+ Thread.sleep(100);
+ return true;
+ });
+
+ EclipseStoreHealthCheck check = EclipseStoreHealthCheck
+ .builder(embeddedStorageManager)
+ .timeout(Duration.of(20, ChronoUnit.MILLIS))
+ .build();
+
+ HealthCheckResponse response = check.call();
+ assertThat(response.status(), is(HealthCheckResponse.Status.DOWN));
+ }
+}
diff --git a/integrations/eclipsestore/metrics/pom.xml b/integrations/eclipsestore/metrics/pom.xml
new file mode 100644
index 00000000000..1ca8454cde6
--- /dev/null
+++ b/integrations/eclipsestore/metrics/pom.xml
@@ -0,0 +1,69 @@
+
+
+
+ 4.0.0
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore-project
+ 4.0.0-SNAPSHOT
+
+
+ helidon-integrations-eclipsestore-metrics
+ Helidon Integrations Eclipse Stream Metrics
+ jar
+
+ Metrics support for Eclipse Stream
+
+
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore
+
+
+ io.helidon.metrics
+ helidon-metrics-api
+
+
+ io.helidon.config
+ helidon-config
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ io.helidon.common.features
+ helidon-common-features-api
+
+
+
+
diff --git a/integrations/eclipsestore/metrics/src/main/java/io/helidon/integrations/eclipsestore/metrics/EclipseStoreHealthMetricsSupport.java b/integrations/eclipsestore/metrics/src/main/java/io/helidon/integrations/eclipsestore/metrics/EclipseStoreHealthMetricsSupport.java
new file mode 100644
index 00000000000..2472e32f386
--- /dev/null
+++ b/integrations/eclipsestore/metrics/src/main/java/io/helidon/integrations/eclipsestore/metrics/EclipseStoreHealthMetricsSupport.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.metrics;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.ToDoubleFunction;
+
+import io.helidon.common.config.Config;
+import io.helidon.metrics.api.Gauge;
+import io.helidon.metrics.api.MeterRegistry;
+import io.helidon.metrics.api.MetricsConfig;
+import io.helidon.metrics.api.MetricsFactory;
+import io.helidon.metrics.api.Tag;
+
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
+import org.eclipse.store.storage.types.StorageRawFileStatistics;
+
+import static io.helidon.metrics.api.Meter.BaseUnits.BYTES;
+
+/**
+ * Helper class that provides the default metrics for an Eclipse Store EmbeddedStorageManager.
+ */
+public class EclipseStoreHealthMetricsSupport {
+
+ private static final String CONFIG_METRIC_ENABLED_VENDOR = "vendor.";
+
+ private static final GaugeInfo GLOBAL_FILE_COUNT =
+ new GaugeInfo<>("eclipsestore.globalFileCount",
+ "Displays the number of storage files.",
+ null,
+ StorageRawFileStatistics::fileCount);
+
+ private static final GaugeInfo LIVE_DATA_LENGTH =
+ new GaugeInfo<>("eclipsestore.liveDataLength",
+ "Displays live data length. This is the 'real' size of the stored data.",
+ BYTES,
+ StorageRawFileStatistics::liveDataLength);
+
+ private static final GaugeInfo TOTAL_DATA_LENGTH =
+ new GaugeInfo<>("eclipsestore.totalDataLength",
+ "Displays total data length. This is the accumulated size of all storage data files.",
+ BYTES,
+ StorageRawFileStatistics::totalDataLength);
+
+ private final Config config;
+ private final EmbeddedStorageManager embeddedStorageManager;
+ private final MeterRegistry vendorRegistry;
+
+ private EclipseStoreHealthMetricsSupport(Builder builder) {
+ super();
+ this.config = builder.config();
+ this.embeddedStorageManager = builder.embeddedStorageManager();
+
+ MetricsFactory metricsFactory;
+ if (builder.metricsFactory() == null) {
+ metricsFactory = MetricsFactory.getInstance(config.get(MetricsConfig.METRICS_CONFIG_KEY));
+ } else {
+ metricsFactory = builder.metricsFactory();
+ }
+
+ this.vendorRegistry = metricsFactory.globalRegistry();
+ }
+
+ /**
+ * Create a new builder to construct an instance.
+ *
+ * @param embeddedStorageManager EmbeddedStorageManager instance that supplies the metrics data.
+ * @return A new builder instance
+ */
+ public static Builder builder(EmbeddedStorageManager embeddedStorageManager) {
+ return new Builder(embeddedStorageManager);
+ }
+
+ private void register(GaugeInfo gaugeInfo, StorageRawFileStatistics stats) {
+ if (config.get(CONFIG_METRIC_ENABLED_VENDOR + gaugeInfo.name + ".enabled")
+ .asBoolean()
+ .orElse(true)) {
+ vendorRegistry.getOrCreate(gaugeInfo.builder(stats));
+ }
+ }
+
+ /**
+ * Register this metrics at the vendor metrics registry.
+ */
+ public void registerMetrics() {
+ StorageRawFileStatistics stats = embeddedStorageManager.createStorageStatistics();
+ register(GLOBAL_FILE_COUNT, stats);
+ register(LIVE_DATA_LENGTH, stats);
+ register(TOTAL_DATA_LENGTH, stats);
+ }
+
+ private record GaugeInfo(String name,
+ String description,
+ String unit,
+ ToDoubleFunction fn,
+ Tag... tags) {
+
+ Gauge.Builder builder(T stateObject) {
+ Gauge.Builder builder = Gauge.builder(name, stateObject, fn)
+ .description(description);
+ if (unit != null) {
+ builder.baseUnit(unit);
+ }
+ if (tags != null) {
+ builder.tags(List.of(tags));
+ }
+ return builder;
+ }
+ }
+
+ /**
+ * A fluent API builder to build instances of {@link io.helidon.integrations.eclipsestore.metrics.EclipseStoreHealthMetricsSupport}.
+ */
+ public static final class Builder implements io.helidon.common.Builder {
+
+ private final EmbeddedStorageManager embeddedStorageManager;
+ private Config config = Config.empty();
+ private MetricsFactory metricsFactory;
+
+ private Builder(EmbeddedStorageManager embeddedStorageManager) {
+ Objects.requireNonNull(embeddedStorageManager);
+ this.embeddedStorageManager = embeddedStorageManager;
+ }
+
+ @Override
+ public EclipseStoreHealthMetricsSupport build() {
+ return new EclipseStoreHealthMetricsSupport(this);
+ }
+
+ /**
+ * get the current configured MetricsFactory.
+ *
+ * @return MetricsFactory
+ */
+ public MetricsFactory metricsFactory() {
+ return this.metricsFactory;
+ }
+
+ /**
+ * get the current configuredEmbeddedStorageManager.
+ *
+ * @return EmbeddedStorageManager
+ */
+ public EmbeddedStorageManager embeddedStorageManager() {
+ return this.embeddedStorageManager;
+ }
+
+ /**
+ * get the current configured helidon configuration.
+ *
+ * @return Config
+ */
+ public Config config() {
+ return this.config;
+ }
+
+ /**
+ * set the MetricsFactory.
+ *
+ * @param metricsFactory metrics factory
+ * @return EclipseStoreHealthMetricsSupport builder
+ */
+ public Builder metricsFactory(MetricsFactory metricsFactory) {
+ this.metricsFactory = metricsFactory;
+ return this;
+ }
+
+ /**
+ * set the helidon configuration used by the builder.
+ *
+ * @param config configuration
+ * @return EclipseStoreHealthMetricsSupport builder
+ */
+ public Builder config(Config config) {
+ this.config = config;
+ return this;
+ }
+ }
+}
diff --git a/integrations/eclipsestore/metrics/src/main/java/io/helidon/integrations/eclipsestore/metrics/package-info.java b/integrations/eclipsestore/metrics/src/main/java/io/helidon/integrations/eclipsestore/metrics/package-info.java
new file mode 100644
index 00000000000..51b75eae2e5
--- /dev/null
+++ b/integrations/eclipsestore/metrics/src/main/java/io/helidon/integrations/eclipsestore/metrics/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides support for Eclipse Store Metrics features integration.
+ */
+package io.helidon.integrations.eclipsestore.metrics;
diff --git a/integrations/eclipsestore/metrics/src/main/java/module-info.java b/integrations/eclipsestore/metrics/src/main/java/module-info.java
new file mode 100644
index 00000000000..b6ffa63d38d
--- /dev/null
+++ b/integrations/eclipsestore/metrics/src/main/java/module-info.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import io.helidon.common.features.api.Aot;
+import io.helidon.common.features.api.Feature;
+import io.helidon.common.features.api.HelidonFlavor;
+/**
+ * Provides support for Eclipse Store Metrics features integration.
+ */
+@Feature(value = "Eclipse Store Metrics",
+ description = "Eclipse Store Metrics Integration",
+ in = HelidonFlavor.SE,
+ path = {"EclipseStore", "Metrics"}
+)
+@Aot(false)
+module io.helidon.integrations.eclipsestore.metrics {
+ requires transitive io.helidon.metrics.api;
+
+ requires transitive io.helidon.integrations.eclipsestore;
+
+ exports io.helidon.integrations.eclipsestore.metrics;
+
+}
diff --git a/integrations/eclipsestore/metrics/src/test/java/io/helidon/integrations/eclipsestore/metrics/EclipseStoreHealthMetricsTest.java b/integrations/eclipsestore/metrics/src/test/java/io/helidon/integrations/eclipsestore/metrics/EclipseStoreHealthMetricsTest.java
new file mode 100644
index 00000000000..60cc43b1fe7
--- /dev/null
+++ b/integrations/eclipsestore/metrics/src/test/java/io/helidon/integrations/eclipsestore/metrics/EclipseStoreHealthMetricsTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.integrations.eclipsestore.metrics;
+
+import io.helidon.metrics.api.Gauge;
+import io.helidon.metrics.api.Metrics;
+import org.eclipse.serializer.util.X;
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
+import org.eclipse.store.storage.types.StorageRawFileStatistics;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.util.Date;
+import java.util.Set;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+// TODO disabled
+@Disabled
+class EclipseStoreHealthMetricsTest {
+
+ @BeforeAll
+ static void init() {
+ EmbeddedStorageManager embeddedStorageManager = Mockito.mock(EmbeddedStorageManager.class);
+
+ Mockito.when(embeddedStorageManager.createStorageStatistics()).thenReturn(
+ StorageRawFileStatistics.New(
+ new Date(System.currentTimeMillis()),
+ 42,
+ 1001,
+ 2002,
+ X.emptyTable()));
+
+ EclipseStoreHealthMetricsSupport.builder(embeddedStorageManager).build().registerMetrics();
+ }
+
+ @Test
+ void testGlobalFileCount() {
+ var firstGauge = findFirstGauge("eclipsestore.globalFileCount");
+
+ long value = (long) firstGauge.value();
+ assertThat("firstGauge eclipsestore.globalFileCount", value, is(42L));
+ }
+
+ @Test
+ void testLivDataLength() {
+ var metricGauge = findFirstGauge("eclipsestore.liveDataLength");
+
+ long value = (long) metricGauge.value();
+ assertThat("metric eclipsestore.liveDataLength", value, is(1001L));
+ }
+
+ @Test
+ void testTotalDataLength() {
+ var firstGauge = findFirstGauge("eclipsestore.totalDataLength");
+
+ long value = (long) firstGauge.value();
+ assertThat("firstGauge eclipsestore.totalDataLength", value, is(2002L));
+ }
+
+ private Gauge> findFirstGauge(String name) {
+ return Metrics.globalRegistry().gauge(name, Set.of()).orElse(null);
+ }
+
+}
diff --git a/integrations/eclipsestore/pom.xml b/integrations/eclipsestore/pom.xml
new file mode 100644
index 00000000000..74f66dfc78c
--- /dev/null
+++ b/integrations/eclipsestore/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+
+ 4.0.0
+
+ io.helidon.integrations
+ helidon-integrations-project
+ 4.0.0-SNAPSHOT
+
+
+ io.helidon.integrations.eclipsestore
+ helidon-integrations-eclipsestore-project
+ Helidon Integrations Eclipse Store Project
+
+ pom
+
+
+ cache
+ cdi
+ core
+ health
+ metrics
+
+
diff --git a/integrations/microstream/README.md b/integrations/microstream/README.md
index c638db7d98d..c320ac08243 100644
--- a/integrations/microstream/README.md
+++ b/integrations/microstream/README.md
@@ -1,5 +1,8 @@
# Microstream integration into Helidon
+**[MICROSTREAM](https://microstream.one/) HAS BECOME [ECLIPSE STORE](https://eclipsestore.io/). HELIDON USERS ARE ENCOURAGED TO TRANSITION TO
+THE EQUIVALENT HELIDON ECLIPSE STORE EXTENSION!**
+
This projects add [Microstream](https://microstream.one) support to Helidon.
The official [Microstream documentation](https://manual.docs.microstream.one/) can be found here.
diff --git a/integrations/microstream/cache/src/main/java/module-info.java b/integrations/microstream/cache/src/main/java/module-info.java
index 650f5931a44..a7c1ca1eba7 100644
--- a/integrations/microstream/cache/src/main/java/module-info.java
+++ b/integrations/microstream/cache/src/main/java/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2023 Oracle and/or its affiliates.
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,4 +26,4 @@
exports io.helidon.integrations.microstream.cache;
-}
\ No newline at end of file
+}
diff --git a/integrations/microstream/cdi/src/main/java/module-info.java b/integrations/microstream/cdi/src/main/java/module-info.java
index 8ab46568393..2804f5d9223 100644
--- a/integrations/microstream/cdi/src/main/java/module-info.java
+++ b/integrations/microstream/cdi/src/main/java/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2023 Oracle and/or its affiliates.
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,14 +17,14 @@
import io.helidon.common.features.api.Aot;
import io.helidon.common.features.api.Feature;
import io.helidon.common.features.api.HelidonFlavor;
-import io.helidon.common.features.api.Preview;
/**
* Provides CDI support for Microstream integration.
*
* @provides jakarta.enterprise.inject.spi.Extension
*/
-@Preview
+
+
@Feature(value = "Microstream",
description = "Microstream Integration",
in = HelidonFlavor.MP,
@@ -37,11 +37,8 @@
requires io.helidon.integrations.microstream.cache;
requires io.helidon.integrations.microstream;
requires jakarta.annotation;
- //requires microstream.base;
requires microstream.cache;
- //requires microstream.persistence;
requires microstream.storage.embedded;
- //requires microstream.storage;
requires static io.helidon.common.features.api;
diff --git a/integrations/microstream/core/src/main/java/module-info.java b/integrations/microstream/core/src/main/java/module-info.java
index 4103e8e5eca..9ce8467ffd6 100644
--- a/integrations/microstream/core/src/main/java/module-info.java
+++ b/integrations/microstream/core/src/main/java/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2023 Oracle and/or its affiliates.
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,12 +17,11 @@
import io.helidon.common.features.api.Aot;
import io.helidon.common.features.api.Feature;
import io.helidon.common.features.api.HelidonFlavor;
-import io.helidon.common.features.api.Preview;
+
/**
* Provides support for Microstream core features integration.
*/
-@Preview
@Feature(value = "Microstream",
description = "Microstream Integration",
in = HelidonFlavor.SE,
diff --git a/integrations/microstream/health/src/main/java/module-info.java b/integrations/microstream/health/src/main/java/module-info.java
index ce9a6bc2800..cad5270803d 100644
--- a/integrations/microstream/health/src/main/java/module-info.java
+++ b/integrations/microstream/health/src/main/java/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2023 Oracle and/or its affiliates.
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,4 +25,4 @@
exports io.helidon.integrations.microstream.health;
-}
\ No newline at end of file
+}
diff --git a/integrations/microstream/metrics/src/main/java/module-info.java b/integrations/microstream/metrics/src/main/java/module-info.java
index dd467958967..ead2132e599 100644
--- a/integrations/microstream/metrics/src/main/java/module-info.java
+++ b/integrations/microstream/metrics/src/main/java/module-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2023 Oracle and/or its affiliates.
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,4 +28,4 @@
exports io.helidon.integrations.microstream.metrics;
-}
\ No newline at end of file
+}
diff --git a/integrations/pom.xml b/integrations/pom.xml
index b4334b274df..02596a6bafa 100644
--- a/integrations/pom.xml
+++ b/integrations/pom.xml
@@ -53,6 +53,7 @@
openapi-ui
vault
microstream
+ eclipsestore
From e6033d3ca270c3cb10110c7a98e734d41e275e4a Mon Sep 17 00:00:00 2001
From: Romain Grecourt
Date: Tue, 19 Mar 2024 16:26:36 -0700
Subject: [PATCH 2/2] gitignore .helidon-oidc-secret
---
.gitignore | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitignore b/.gitignore
index b1bf6a636d4..6918d53ea85 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,3 +81,5 @@ docs/se/config/images
# Baseline results for regression tests
jmh-baseline.json
+
+.helidon-oidc-secret