Skip to content

Refresh of the guide [DEX-296] #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ '8' ]
java: [ '17', '23' ]
architecture: [ 'x64' ]
name: Build with JDK ${{ matrix.java }} on ${{ matrix.architecture }}
steps:
Expand All @@ -30,5 +30,5 @@ jobs:
restore-keys: ${{ runner.os }}-maven-

- name: Run Tests
run: mvn verify -Ptests
run: mvn verify

12 changes: 12 additions & 0 deletions .run/Template JUnit.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="true" type="JUnit" factoryName="JUnit">
<module name="hazelcast-embedded-springboot" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea -Djava.net.preferIPv4Stack=true" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
39 changes: 28 additions & 11 deletions docs/modules/ROOT/pages/hazelcast-embedded-springboot.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,58 +30,75 @@ If Hazelcast is on the classpath and a suitable configuration is found, Spring B
include::ROOT:example$hazelcast-embedded-springboot/pom.xml[tag=hazelcast-dep]
----

Hazelcast configuration (`hazelcast.yaml`) is placed in the `src/main/resources/` directory. You only need to auto-wire the `HazelcastInstance` bean in the `CommandController` and use it to access to Hazelcast data structures:
Hazelcast configuration (`hazelcast.yaml`) is placed in the `src/main/resources/` directory. You only need to define `map` bean, if you want to autowire the IMap instance:
[source,java,indent=0]
----
include::ROOT:example$hazelcast-embedded-springboot/src/main/java/guides/hazelcast/springboot/HazelcastApplication.java[tag=imap-bean]
----

Bean will have name "map" and can be autowired by `IMap` type (if it's the only IMap added as bean).

Now you can autowire the `IMap` bean in the `CommandController` and use it to access the Hazelcast structure:

[source,java,indent=0]
----
include::ROOT:example$hazelcast-embedded-springboot/src/main/java/guides/hazelcast/springboot/CommandController.java[]
----

Please notice, that we've used `@Qualifier("map")` - it's strictly speaking optional, but once you add more IMaps, you will need to distinguish which map you want to autowire.

== Run the Sample Application

Run the application using Maven in a terminal:

[source,bash]
----
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=8080"
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=8080 -Djava.net.preferIPv4Stack=true"
----

Then, rerun the application in another terminal.

NOTE: Notice the different value for the `server.port` argument.

NOTE: We've used `-Djava.net.preferIPv4Stack=true`, because on some platforms there are problems with multicast on IPv6. Adding this option ensures smooth run when learning.

[source,bash]
----
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=8081"
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=8081 -Djava.net.preferIPv4Stack=true"
----

After both application instances are initialized, you should see that the Hazelcast cluster is formed:

```bash
[source,bash]
----
Members {size:2, ver:2} [
Member [192.168.1.64]:5701 - 520aec3f-58a6-4fcb-a3c7-498dcf37d8ff
Member [192.168.1.64]:5702 - 5c03e467-d457-4847-b49a-745a335db557 this
]
```
----

Now, you can issue HTTP requests to put and get data back. Run the following command to put the data into a Hazelcast distributed map:

```bash
[source,bash]
----
curl --data "key=key1&value=hazelcast" "localhost:8080/put"
```
----

You will see the value in the output. Then run the command below to get the data back. Please note that the call is made to the other application instance:

```bash
[source,bash]
----
curl "localhost:8081/get?key=key1"
```
----

Again, you will see the value in the output since the data is distributed among Hazelcast cluster instances and can be accessed from any of them.
Again, you will see the value in the output (`{"value":"hazelcast"}`), because the data is distributed among Hazelcast cluster instances and can be accessed from any of them.

== Test the Application

To run the integration tests, run the following command in terminal. But before, make sure to kill the running application instances.

----
mvn verify -Ptests
mvn verify
----

If the tests pass, you’ll see a similar output to the following:
Expand Down
65 changes: 38 additions & 27 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/>
<version>3.4.1</version>
</parent>

<properties>
<java.version>1.8</java.version>
<hazelcast.version>5.3.2</hazelcast.version>
<java.version>17</java.version>
<hazelcast.version>5.5.0</hazelcast.version>
</properties>

<build>
Expand All @@ -26,35 +25,34 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.5.2</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<argLine>-Djava.net.preferIPv4Stack=true</argLine>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>tests</id>
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- tag::hazelcast-dep[] -->
<dependency>
Expand All @@ -74,11 +72,24 @@
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-spring-boot</artifactId>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>2.3</version>
<version>2.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.2.2</version>
</dependency>
</dependencies>
</project>
17 changes: 6 additions & 11 deletions src/main/java/guides/hazelcast/springboot/CommandController.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
package guides.hazelcast.springboot;

import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.IMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.ConcurrentMap;

@RestController
public class CommandController {
@Autowired
private HazelcastInstance hazelcastInstance;

private ConcurrentMap<String,String> retrieveMap() {
return hazelcastInstance.getMap("map");
}
@Autowired @Qualifier("map")
private IMap<String, String> map;

@PostMapping("/put")
public CommandResponse put(@RequestParam(value = "key") String key, @RequestParam(value = "value") String value) {
retrieveMap().put(key, value);
map.put(key, value);
return new CommandResponse(value);
}

@GetMapping("/get")
public CommandResponse get(@RequestParam(value = "key") String key) {
String value = retrieveMap().get(key);
String value = map.get(key);
return new CommandResponse(value);
}
}
16 changes: 1 addition & 15 deletions src/main/java/guides/hazelcast/springboot/CommandResponse.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
package guides.hazelcast.springboot;

public class CommandResponse {

private String value;

public CommandResponse(String value) {
this.value = value;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}
public record CommandResponse (String value) {
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package guides.hazelcast.springboot;

import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.IMap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
Expand All @@ -10,4 +13,11 @@ public class HazelcastApplication {
public static void main(String[] args) {
SpringApplication.run(HazelcastApplication.class, args);
}

//tag::imap-bean[]
@Bean
public IMap<String, String> map(HazelcastInstance instance) {
return instance.getMap("map");
}
//end::imap-bean[]
}
8 changes: 7 additions & 1 deletion src/main/resources/hazelcast.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
hazelcast:
cluster-name: hazelcast-cluster
cluster-name: hazelcast-cluster
properties:
hazelcast.logging.type: log4j2
network:
join:
multicast:
enabled: true
13 changes: 13 additions & 0 deletions src/main/resources/log4j2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ERROR">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{ABSOLUTE} %5p |%X{test-name}| - [%c{1}] %t - %m%n" />
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
40 changes: 26 additions & 14 deletions src/test/java/guides/hazelcast/springboot/CommandControllerIT.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package guides.hazelcast.springboot;

import com.hazelcast.config.Config;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import org.junit.jupiter.api.Test;
Expand All @@ -9,7 +10,9 @@
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;

import static org.junit.jupiter.api.Assertions.assertEquals;
import java.time.Duration;

import static org.awaitility.Awaitility.await;
import static org.springframework.http.HttpHeaders.ACCEPT;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
Expand All @@ -26,7 +29,11 @@ public class CommandControllerIT {
@Test
public void testPutRequest(){
//when
WebTestClient.ResponseSpec responseSpec = makePostRequest("/put?key={key}&value={value}", "key1", "value1");
WebTestClient.ResponseSpec responseSpec = webTestClient
.post()
.uri("/put?key={key}&value={value}", "key1", "value1")
.header(ACCEPT, APPLICATION_JSON_VALUE)
.exchange();

//then
responseSpec.expectStatus()
Expand All @@ -40,7 +47,11 @@ public void testPutRequest(){
@Test
public void testGetRequest(){
//given
makePostRequest("/put?key={key}&value={value}", "key1", "value1");
webTestClient
.post()
.uri("/put?key={key}&value={value}", "key1", "value1")
.header(ACCEPT, APPLICATION_JSON_VALUE)
.exchange();

//when
WebTestClient.ResponseSpec responseSpec = webTestClient
Expand All @@ -58,20 +69,21 @@ public void testGetRequest(){
.jsonPath("$.value").isEqualTo("value1");
}

private WebTestClient.ResponseSpec makePostRequest(String uri, Object... parameters) {
return webTestClient
.post()
.uri(uri, parameters)
.header(ACCEPT, APPLICATION_JSON_VALUE)
.exchange();
}

@Test
public void testHazelcastCluster(){
public void testHazelcastCluster() {
Config config = Config.load();
config.setProperty("hazelcast.logging.type", "log4j2");

//given
Hazelcast.newHazelcastInstance();
HazelcastInstance hz = Hazelcast.newHazelcastInstance();

//then
assertEquals(2, hazelcastInstance.getCluster().getMembers().size());
try {
await()
.atMost(Duration.ofMinutes(2))
.until(() -> hazelcastInstance.getCluster().getMembers().size() == 2);
} finally {
hz.shutdown();
}
}
}
Loading
Loading