You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2023/12/30 18:09:28 UTC
(plc4x) branch feature/new-ui-tool updated: feat: Implemented a way to send server-events to the frontend using websockets (Implemented on the server-side and not yet in the frontend application, receiving messages using ws.html only)
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/new-ui-tool
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/feature/new-ui-tool by this push:
new c0d4fc84fe feat: Implemented a way to send server-events to the frontend using websockets (Implemented on the server-side and not yet in the frontend application, receiving messages using ws.html only)
c0d4fc84fe is described below
commit c0d4fc84fe1a08333365c6c716a5b51c70ff21cc
Author: Christofer Dutz <cd...@apache.org>
AuthorDate: Sat Dec 30 19:09:19 2023 +0100
feat: Implemented a way to send server-events to the frontend using websockets (Implemented on the server-side and not yet in the frontend application, receiving messages using ws.html only)
---
plc4j/tools/ui/backend/pom.xml | 81 ++++++++++++-----
.../java/tools/ui/Plc4xUiBackendApplication.java | 9 +-
.../Plc4xConfiguration.java} | 16 ++--
.../tools/ui/configuration/WebSocketConfig.java | 43 +++++++++
.../tools/ui/controller/ConnectionController.java | 62 +++++++++++++
.../java/tools/ui/controller/DriverController.java | 69 ++++----------
.../ApplicationEvent.java} | 22 +++--
.../DeviceEvent.java} | 12 +--
.../EventType.java} | 14 +--
.../java/tools/ui/handler/WebSocketHandler.java | 101 +++++++++++++++++++++
.../ConnectionService.java => model/Device.java} | 25 +++--
.../ConnectionRepository.java} | 14 +--
.../java/tools/ui/service/ConnectionService.java | 37 +++++++-
.../DriverService.java} | 72 +++++++++------
.../src/main/resources/application.properties | 10 ++
plc4j/tools/ui/backend/ws.html | 36 ++++++++
plc4j/tools/ui/frontend/frontend/package.json | 9 ++
.../src/generated/plc4j-tools-ui-frontend.ts | 42 ++++++---
.../ui/frontend/frontend/src/pages/Inspect.tsx | 8 +-
plc4j/tools/ui/frontend/pom.xml | 1 +
plc4j/tools/ui/pom.xml | 29 ++++++
21 files changed, 540 insertions(+), 172 deletions(-)
diff --git a/plc4j/tools/ui/backend/pom.xml b/plc4j/tools/ui/backend/pom.xml
index 0d5f8a1633..78cce151c8 100644
--- a/plc4j/tools/ui/backend/pom.xml
+++ b/plc4j/tools/ui/backend/pom.xml
@@ -37,6 +37,10 @@
<usedDependencies combine.children="append">
<usedDependency>org.apache.plc4x:plc4j-driver-all</usedDependency>
<usedDependency>org.springframework.boot:spring-boot-starter-web</usedDependency>
+ <usedDependency>org.springframework.boot:spring-boot-starter-websocket</usedDependency>
+ <usedDependency>org.springframework.boot:spring-boot-starter-data-jpa</usedDependency>
+ <usedDependency>org.apache.derby:derby</usedDependency>
+ <usedDependency>org.apache.derby:derbytools</usedDependency>
<usedDependency>ch.qos.logback:logback-core</usedDependency>
</usedDependencies>
</configuration>
@@ -47,23 +51,57 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- <version>3.1.5</version>
+ <artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
- <version>3.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot</artifactId>
- <version>3.1.5</version>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-websocket</artifactId>
+ </dependency>
+ <!--dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-core</artifactId>
+ </dependency-->
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
- <version>6.0.13</version>
+ </dependency>
+ <!--dependency>
+ <groupId>org.springframework.data</groupId>
+ <artifactId>spring-data-commons</artifactId>
+ </dependency-->
+ <dependency>
+ <groupId>org.springframework.data</groupId>
+ <artifactId>spring-data-jpa</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-websocket</artifactId>
+ </dependency>
+
+ <!-- Add support for the embedded derby database, which is used for saving the configuration -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-jpa</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derbytools</artifactId>
</dependency>
<dependency>
@@ -88,10 +126,22 @@
<type>pom</type>
</dependency>
+ <dependency>
+ <groupId>jakarta.persistence</groupId>
+ <artifactId>jakarta.persistence-api</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </dependency>
+ <!--dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ </dependency-->
<dependency>
<groupId>org.slf4j</groupId>
@@ -112,42 +162,23 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
- <version>3.1.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
- <version>3.1.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
- <version>6.0.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
- <version>6.1.5</version>
<scope>test</scope>
</dependency>
</dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.aspectj</groupId>
- <artifactId>aspectjweaver</artifactId>
- <version>1.9.20.1</version>
- </dependency>
- <dependency>
- <groupId>jakarta.annotation</groupId>
- <artifactId>jakarta.annotation-api</artifactId>
- <version>2.1.1</version>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
</project>
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/Plc4xUiBackendApplication.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/Plc4xUiBackendApplication.java
index 79dbec6a7b..c6290bef30 100644
--- a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/Plc4xUiBackendApplication.java
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/Plc4xUiBackendApplication.java
@@ -21,13 +21,14 @@ package org.apache.plc4x.java.tools.ui;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.ComponentScan;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
+@EnableJpaRepositories("org.apache.plc4x.java.tools.ui")
public class Plc4xUiBackendApplication {
- public static void main(String[] args) {
- SpringApplication.run(Plc4xUiBackendApplication.class, args);
- }
+ public static void main(String[] args) {
+ SpringApplication.run(Plc4xUiBackendApplication.class, args);
+ }
}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/configuration/Plc4xConfiguration.java
similarity index 68%
copy from plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
copy to plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/configuration/Plc4xConfiguration.java
index 1d2299a4f9..1b79413fd6 100644
--- a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/configuration/Plc4xConfiguration.java
@@ -17,16 +17,18 @@
* under the License.
*/
-package org.apache.plc4x.java.tools.ui.service;
+package org.apache.plc4x.java.tools.ui.configuration;
-import org.apache.plc4x.java.utils.cache.CachedPlcConnectionManager;
+import org.apache.plc4x.java.api.PlcDriverManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
-public class ConnectionService {
+@Configuration
+public class Plc4xConfiguration {
- private final CachedPlcConnectionManager cachedPlcConnectionManager;
-
- public ConnectionService() {
- cachedPlcConnectionManager = CachedPlcConnectionManager.getBuilder().build();
+ @Bean
+ public PlcDriverManager driverManager() {
+ return PlcDriverManager.getDefault();
}
}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/configuration/WebSocketConfig.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/configuration/WebSocketConfig.java
new file mode 100644
index 0000000000..18d3d0f98d
--- /dev/null
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/configuration/WebSocketConfig.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.plc4x.java.tools.ui.configuration;
+
+import org.apache.plc4x.java.tools.ui.handler.WebSocketHandler;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
+
+@Configuration
+@EnableWebSocket
+public class WebSocketConfig implements WebSocketConfigurer {
+
+ private final WebSocketHandler webSocketHandler;
+
+ public WebSocketConfig(WebSocketHandler webSocketHandler) {
+ this.webSocketHandler = webSocketHandler;
+ }
+
+ @Override
+ public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
+ registry.addHandler(webSocketHandler, "/ws").setAllowedOrigins("*");
+ }
+
+}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/controller/ConnectionController.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/controller/ConnectionController.java
new file mode 100644
index 0000000000..9f5ef46bb9
--- /dev/null
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/controller/ConnectionController.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.plc4x.java.tools.ui.controller;
+
+import org.apache.plc4x.java.tools.ui.model.Device;
+import org.apache.plc4x.java.tools.ui.service.ConnectionService;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/connections")
+public class ConnectionController {
+
+ private final ConnectionService connectionService;
+
+ public ConnectionController(ConnectionService connectionService) {
+ this.connectionService = connectionService;
+ }
+
+ @GetMapping("/{id}")
+ public Device getConnectionById(@PathVariable Integer id) {
+ return connectionService.readConnection(id).orElseThrow(() -> new RuntimeException("Error finding connection with id: " + id));
+ }
+
+ @GetMapping
+ public List<Device> getAllConnections() {
+ return connectionService.getAllConnections();
+ }
+
+ @PostMapping
+ public Device saveConnection(@RequestBody Device device) {
+ if (device.getId() == null) {
+ return connectionService.createConnection(device);
+ } else {
+ return connectionService.updateConnection(device);
+ }
+ }
+
+ @DeleteMapping
+ public void deleteConnection(@RequestBody Device device) {
+ connectionService.deleteConnection(device);
+ }
+
+}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/controller/DriverController.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/controller/DriverController.java
index 8919f284dc..3b7c7e7c73 100644
--- a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/controller/DriverController.java
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/controller/DriverController.java
@@ -19,70 +19,33 @@
package org.apache.plc4x.java.tools.ui.controller;
-import org.apache.commons.lang3.reflect.FieldUtils;
-import org.apache.plc4x.java.api.PlcDriver;
-import org.apache.plc4x.java.api.PlcDriverManager;
-import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.api.metadata.PlcDriverMetadata;
-import org.apache.plc4x.java.spi.configuration.ConfigurationFactory;
-import org.apache.plc4x.java.spi.configuration.annotations.ComplexConfigurationParameter;
-import org.apache.plc4x.java.spi.configuration.annotations.ConfigurationParameter;
-import org.apache.plc4x.java.spi.configuration.annotations.Required;
-import org.apache.plc4x.java.tools.ui.model.ConfigurationOption;
import org.apache.plc4x.java.tools.ui.model.Driver;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.CrossOrigin;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.apache.plc4x.java.tools.ui.service.DriverService;
+import org.springframework.web.bind.annotation.*;
-import java.lang.reflect.Field;
-import java.util.*;
-import java.util.function.Function;
-import java.util.stream.Collectors;
+import java.util.List;
// Allow from the default port 8080 as well as the one node usually uses for it's dev-mode 5173
-@CrossOrigin(origins = {"http://localhost:8080", "http://localhost:5173"})
+//@CrossOrigin(origins = {"http://localhost:8080", "http://localhost:5173"})
+@CrossOrigin(origins = {"*"})
@RestController
@RequestMapping("/api")
public class DriverController {
- @GetMapping("/drivers")
- public ResponseEntity<List<Driver>> getDriverList() {
- List<Driver> drivers = new ArrayList<>();
-
- // Build a list of driver objects.
- PlcDriverManager driverManager = PlcDriverManager.getDefault();
- for (String protocolCode : driverManager.listDrivers()) {
- try {
- PlcDriver driver = driverManager.getDriver(protocolCode);
- PlcDriverMetadata metadata = driver.getMetadata();
-
- // Get a description of all supported configuration options of the given driver.
- Class<?> configurationType = driver.getConfigurationType();
- Map<String, ConfigurationOption> configurationOptions = Arrays.stream(FieldUtils.getAllFields(configurationType))
- // - Filter out only the ones annotated with the ConfigurationParameter annotation.
- .filter(field -> (field.getAnnotation(ConfigurationParameter.class) != null) || (field.getAnnotation(ComplexConfigurationParameter.class) != null))
- .map(field -> new ConfigurationOption(field.getName(), field.getType().getTypeName(), field.isAnnotationPresent(Required.class), ConfigurationFactory.getDefaultValueFromAnnotation(field)))
- // - Create a map with the field-name as key and the field itself as value.
- .collect(Collectors.toMap(
- ConfigurationOption::getName,
- Function.identity()
- ));
-
- // TODO: Get a list of all directly supported transports and for each a list of the configuration options.
+ private final DriverService driverService;
- drivers.add(new Driver(protocolCode, driver.getProtocolName(), metadata.canDiscover(), configurationOptions, null));
- } catch (Exception e) {
- e.printStackTrace();
- // Ignore ...
- }
- }
+ public DriverController(DriverService driverService) {
+ this.driverService = driverService;
+ }
- // Sort the list by the code of the driver elements.
- drivers.sort(Comparator.comparing(Driver::getCode));
+ @GetMapping("/drivers")
+ public List<Driver> getDriverList() {
+ return driverService.getDriverList();
+ }
- return ResponseEntity.ok(drivers);
+ @GetMapping("/discover/{protocolCode}")
+ public void discover(@PathVariable("protocolCode") String protocolCode) {
+ driverService.discover(protocolCode);
}
}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/event/ApplicationEvent.java
similarity index 58%
copy from plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
copy to plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/event/ApplicationEvent.java
index 1d2299a4f9..6eab967421 100644
--- a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/event/ApplicationEvent.java
@@ -17,16 +17,26 @@
* under the License.
*/
-package org.apache.plc4x.java.tools.ui.service;
+package org.apache.plc4x.java.tools.ui.event;
-import org.apache.plc4x.java.utils.cache.CachedPlcConnectionManager;
+public abstract class ApplicationEvent<T> extends org.springframework.context.ApplicationEvent {
-public class ConnectionService {
+ private final EventType eventType;
- private final CachedPlcConnectionManager cachedPlcConnectionManager;
+ public ApplicationEvent(T source, EventType eventType) {
+ super(source);
+ this.eventType = eventType;
+ }
+
+ public EventType getEventType() {
+ return eventType;
+ }
- public ConnectionService() {
- cachedPlcConnectionManager = CachedPlcConnectionManager.getBuilder().build();
+ @Override
+ public T getSource() {
+ // We're only accepting objects of type T, so in this case it's safe to cast.
+ //noinspection unchecked
+ return (T) super.getSource();
}
}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/event/DeviceEvent.java
similarity index 70%
copy from plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
copy to plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/event/DeviceEvent.java
index 1d2299a4f9..d9693b7c39 100644
--- a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/event/DeviceEvent.java
@@ -17,16 +17,14 @@
* under the License.
*/
-package org.apache.plc4x.java.tools.ui.service;
+package org.apache.plc4x.java.tools.ui.event;
-import org.apache.plc4x.java.utils.cache.CachedPlcConnectionManager;
+import org.apache.plc4x.java.tools.ui.model.Device;
-public class ConnectionService {
+public class DeviceEvent extends ApplicationEvent<Device> {
- private final CachedPlcConnectionManager cachedPlcConnectionManager;
-
- public ConnectionService() {
- cachedPlcConnectionManager = CachedPlcConnectionManager.getBuilder().build();
+ public DeviceEvent(Device source, EventType eventType) {
+ super(source, eventType);
}
}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/event/EventType.java
similarity index 69%
copy from plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
copy to plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/event/EventType.java
index 1d2299a4f9..a7613333b1 100644
--- a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/event/EventType.java
@@ -17,16 +17,12 @@
* under the License.
*/
-package org.apache.plc4x.java.tools.ui.service;
+package org.apache.plc4x.java.tools.ui.event;
-import org.apache.plc4x.java.utils.cache.CachedPlcConnectionManager;
+public enum EventType {
-public class ConnectionService {
-
- private final CachedPlcConnectionManager cachedPlcConnectionManager;
-
- public ConnectionService() {
- cachedPlcConnectionManager = CachedPlcConnectionManager.getBuilder().build();
- }
+ CREATED,
+ UPDATED,
+ DELETED
}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/handler/WebSocketHandler.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/handler/WebSocketHandler.java
new file mode 100644
index 0000000000..8dbd33dea2
--- /dev/null
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/handler/WebSocketHandler.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.plc4x.java.tools.ui.handler;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.plc4x.java.tools.ui.event.ApplicationEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketMessage;
+import org.springframework.web.socket.WebSocketSession;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+public class WebSocketHandler implements org.springframework.web.socket.WebSocketHandler {
+
+ private final Map<String, WebSocketSession> openSessions = new ConcurrentHashMap<>();
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ /**
+ * ApplicationEvent listener forwarding all ApplicationEvents from this application to all connected clients.
+ * @param applicationEvent event that we want to be forwarded.
+ */
+ @EventListener
+ public void onApplicationEvent(ApplicationEvent<?> applicationEvent) {
+ openSessions.forEach((s, webSocketSession) -> {
+ try {
+ webSocketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(applicationEvent)));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
+ /**
+ * Register a new web-socket session.
+ * @param session the new web-socket session.
+ */
+ @Override
+ public void afterConnectionEstablished(WebSocketSession session) {
+ openSessions.put(session.getId(), session);
+ }
+
+ /**
+ * Remove a web-socket session from the list.
+ * @param session the web-socket session we want to remove
+ * @param closeStatus the status of the closed session
+ */
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
+ openSessions.remove(session.getId());
+ }
+
+ /**
+ * Handle an incoming message on the web-socket session
+ * (this should actually not happen, as we only use the web-sockets for server-to-client communication)
+ * @param session the web-socket session the message is coming in on
+ * @param message the message
+ */
+ @Override
+ public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) {
+ System.out.println("handleMessage");
+ }
+
+ /**
+ * Callback for handling transport errors.
+ * @param session the web-socket session causing the error
+ * @param exception the error that happened
+ */
+ @Override
+ public void handleTransportError(WebSocketSession session, Throwable exception) {
+ System.out.println("handleTransportError");
+ }
+
+ @Override
+ public boolean supportsPartialMessages() {
+ return false;
+ }
+
+}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/model/Device.java
similarity index 64%
copy from plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
copy to plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/model/Device.java
index 1d2299a4f9..4e7e702fa8 100644
--- a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/model/Device.java
@@ -17,16 +17,29 @@
* under the License.
*/
-package org.apache.plc4x.java.tools.ui.service;
+package org.apache.plc4x.java.tools.ui.model;
-import org.apache.plc4x.java.utils.cache.CachedPlcConnectionManager;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
-public class ConnectionService {
+@Entity
+public class Device {
- private final CachedPlcConnectionManager cachedPlcConnectionManager;
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Integer id;
- public ConnectionService() {
- cachedPlcConnectionManager = CachedPlcConnectionManager.getBuilder().build();
+ public Device() {
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
}
}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/repository/ConnectionRepository.java
similarity index 69%
copy from plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
copy to plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/repository/ConnectionRepository.java
index 1d2299a4f9..52b0de3f56 100644
--- a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/repository/ConnectionRepository.java
@@ -17,16 +17,10 @@
* under the License.
*/
-package org.apache.plc4x.java.tools.ui.service;
+package org.apache.plc4x.java.tools.ui.repository;
-import org.apache.plc4x.java.utils.cache.CachedPlcConnectionManager;
-
-public class ConnectionService {
-
- private final CachedPlcConnectionManager cachedPlcConnectionManager;
-
- public ConnectionService() {
- cachedPlcConnectionManager = CachedPlcConnectionManager.getBuilder().build();
- }
+import org.apache.plc4x.java.tools.ui.model.Device;
+import org.springframework.data.jpa.repository.JpaRepository;
+public interface ConnectionRepository extends JpaRepository<Device, Integer> {
}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
index 1d2299a4f9..2cffd94501 100644
--- a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/ConnectionService.java
@@ -19,14 +19,47 @@
package org.apache.plc4x.java.tools.ui.service;
+import org.apache.plc4x.java.api.PlcDriverManager;
+import org.apache.plc4x.java.tools.ui.model.Device;
+import org.apache.plc4x.java.tools.ui.repository.ConnectionRepository;
import org.apache.plc4x.java.utils.cache.CachedPlcConnectionManager;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+import java.util.List;
+import java.util.Optional;
+
+@Component
public class ConnectionService {
+ private final ConnectionRepository connectionRepository;
+ private final ApplicationEventPublisher publisher;
private final CachedPlcConnectionManager cachedPlcConnectionManager;
- public ConnectionService() {
- cachedPlcConnectionManager = CachedPlcConnectionManager.getBuilder().build();
+ public ConnectionService(ConnectionRepository connectionRepository, ApplicationEventPublisher publisher, PlcDriverManager driverManager) {
+ this.connectionRepository = connectionRepository;
+ this.publisher = publisher;
+ this.cachedPlcConnectionManager = CachedPlcConnectionManager.getBuilder(driverManager.getConnectionManager()).build();
+ }
+
+ public List<Device> getAllConnections() {
+ return connectionRepository.findAll();
+ }
+
+ public Device createConnection(Device device) {
+ return connectionRepository.save(device);
+ }
+
+ public Optional<Device> readConnection(Integer id) {
+ return connectionRepository.findById(id);
+ }
+
+ public Device updateConnection(Device device) {
+ return connectionRepository.save(device);
+ }
+
+ public void deleteConnection(Device device) {
+ connectionRepository.delete(device);
}
}
diff --git a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/controller/DriverController.java b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/DriverService.java
similarity index 58%
copy from plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/controller/DriverController.java
copy to plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/DriverService.java
index 8919f284dc..170d518cc9 100644
--- a/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/controller/DriverController.java
+++ b/plc4j/tools/ui/backend/src/main/java/org/apache/plc4x/java/tools/ui/service/DriverService.java
@@ -17,42 +17,47 @@
* under the License.
*/
-package org.apache.plc4x.java.tools.ui.controller;
+package org.apache.plc4x.java.tools.ui.service;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.plc4x.java.api.PlcDriver;
import org.apache.plc4x.java.api.PlcDriverManager;
import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
+import org.apache.plc4x.java.api.messages.PlcDiscoveryRequest;
import org.apache.plc4x.java.api.metadata.PlcDriverMetadata;
import org.apache.plc4x.java.spi.configuration.ConfigurationFactory;
import org.apache.plc4x.java.spi.configuration.annotations.ComplexConfigurationParameter;
import org.apache.plc4x.java.spi.configuration.annotations.ConfigurationParameter;
import org.apache.plc4x.java.spi.configuration.annotations.Required;
+import org.apache.plc4x.java.tools.ui.event.DeviceEvent;
+import org.apache.plc4x.java.tools.ui.event.EventType;
import org.apache.plc4x.java.tools.ui.model.ConfigurationOption;
+import org.apache.plc4x.java.tools.ui.model.Device;
import org.apache.plc4x.java.tools.ui.model.Driver;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.CrossOrigin;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
-import java.lang.reflect.Field;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
-// Allow from the default port 8080 as well as the one node usually uses for it's dev-mode 5173
-@CrossOrigin(origins = {"http://localhost:8080", "http://localhost:5173"})
-@RestController
-@RequestMapping("/api")
-public class DriverController {
+@Component
+public class DriverService {
- @GetMapping("/drivers")
- public ResponseEntity<List<Driver>> getDriverList() {
- List<Driver> drivers = new ArrayList<>();
+ private final PlcDriverManager driverManager;
+
+ private final ApplicationEventPublisher applicationEventPublisher;
- // Build a list of driver objects.
- PlcDriverManager driverManager = PlcDriverManager.getDefault();
+ public DriverService(PlcDriverManager driverManager, ApplicationEventPublisher applicationEventPublisher) {
+ this.driverManager = driverManager;
+ this.applicationEventPublisher = applicationEventPublisher;
+ }
+
+ public List<Driver> getDriverList() {
+ List<Driver> drivers = new ArrayList<>();
for (String protocolCode : driverManager.listDrivers()) {
try {
PlcDriver driver = driverManager.getDriver(protocolCode);
@@ -61,10 +66,8 @@ public class DriverController {
// Get a description of all supported configuration options of the given driver.
Class<?> configurationType = driver.getConfigurationType();
Map<String, ConfigurationOption> configurationOptions = Arrays.stream(FieldUtils.getAllFields(configurationType))
- // - Filter out only the ones annotated with the ConfigurationParameter annotation.
.filter(field -> (field.getAnnotation(ConfigurationParameter.class) != null) || (field.getAnnotation(ComplexConfigurationParameter.class) != null))
.map(field -> new ConfigurationOption(field.getName(), field.getType().getTypeName(), field.isAnnotationPresent(Required.class), ConfigurationFactory.getDefaultValueFromAnnotation(field)))
- // - Create a map with the field-name as key and the field itself as value.
.collect(Collectors.toMap(
ConfigurationOption::getName,
Function.identity()
@@ -74,15 +77,32 @@ public class DriverController {
drivers.add(new Driver(protocolCode, driver.getProtocolName(), metadata.canDiscover(), configurationOptions, null));
} catch (Exception e) {
- e.printStackTrace();
- // Ignore ...
+ throw new RuntimeException("Error retrieving driver list", e);
}
}
+ return drivers;
+ }
- // Sort the list by the code of the driver elements.
- drivers.sort(Comparator.comparing(Driver::getCode));
-
- return ResponseEntity.ok(drivers);
+ public void discover(String protocolCode) {
+ try {
+ PlcDriver driver = driverManager.getDriver(protocolCode);
+ if (!driver.getMetadata().canDiscover()) {
+ throw new RuntimeException("Driver doesn't support discovery");
+ } else {
+ PlcDiscoveryRequest request = driver.discoveryRequestBuilder().addQuery("all", "*").build();
+ // Execute the discovery request and have all connections found be added as connections.
+ request.executeWithHandler(discoveryItem -> {
+ Device device = new Device();
+ applicationEventPublisher.publishEvent(new DeviceEvent(device, EventType.CREATED));
+ }).whenComplete((plcDiscoveryResponse, throwable) -> {
+ if(throwable != null) {
+ throw new RuntimeException("Error executing discovery", throwable);
+ }
+ });
+ }
+ } catch (PlcConnectionException e) {
+ throw new RuntimeException("Error getting driver", e);
+ }
}
}
diff --git a/plc4j/tools/ui/backend/src/main/resources/application.properties b/plc4j/tools/ui/backend/src/main/resources/application.properties
index fe95886d5c..4909f699b8 100644
--- a/plc4j/tools/ui/backend/src/main/resources/application.properties
+++ b/plc4j/tools/ui/backend/src/main/resources/application.properties
@@ -16,3 +16,13 @@
# specific language governing permissions and limitations
# under the License.
#
+
+# Settings for the Derby sql database, which contains the application settings.
+spring.jpa.generate-ddl=true
+spring.jpa.hibernate.ddl-auto=update
+spring.jpa.database=default
+spring.datasource.url=jdbc:derby:directory:storage/settings;create=true
+
+# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
+spring.sql.init.continue-on-error=false
+spring.datasource.generate-unique-name=false
diff --git a/plc4j/tools/ui/backend/ws.html b/plc4j/tools/ui/backend/ws.html
new file mode 100644
index 0000000000..492e0ae106
--- /dev/null
+++ b/plc4j/tools/ui/backend/ws.html
@@ -0,0 +1,36 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Profile notification client
+ </title>
+</head>
+<body>
+<script>
+ // <1>
+ var socket = new WebSocket('ws://localhost:8080/ws');
+ // <2>
+ socket.addEventListener('message', function (event) {
+ window.alert('message from server: ' + event.data);
+ });
+</script>
+</body>
+</html>
diff --git a/plc4j/tools/ui/frontend/frontend/package.json b/plc4j/tools/ui/frontend/frontend/package.json
index 85e36de331..cd38560982 100644
--- a/plc4j/tools/ui/frontend/frontend/package.json
+++ b/plc4j/tools/ui/frontend/frontend/package.json
@@ -35,5 +35,14 @@
"eslint-plugin-react-refresh": "^0.4.4",
"typescript": "^5.2.2",
"vite": "^5.0.0"
+ },
+ "proxy": {
+ "/ws": {
+ "target": "ws://localhost:8080",
+ "ws": true
+ },
+ "/": {
+ "target": "http://localhost:8080"
+ }
}
}
diff --git a/plc4j/tools/ui/frontend/frontend/src/generated/plc4j-tools-ui-frontend.ts b/plc4j/tools/ui/frontend/frontend/src/generated/plc4j-tools-ui-frontend.ts
index 79d344b313..1c2b82183a 100644
--- a/plc4j/tools/ui/frontend/frontend/src/generated/plc4j-tools-ui-frontend.ts
+++ b/plc4j/tools/ui/frontend/frontend/src/generated/plc4j-tools-ui-frontend.ts
@@ -19,7 +19,7 @@
*/
/* tslint:disable */
/* eslint-disable */
-// Generated using typescript-generator version 3.2.1263 on 2023-12-26 16:21:15.
+// Generated using typescript-generator version 3.2.1263 on 2023-12-29 16:56:08.
export interface PlcBrowseItem {
name: string;
@@ -27,8 +27,8 @@ export interface PlcBrowseItem {
writable: boolean;
children: { [index: string]: PlcBrowseItem };
tag: PlcTag;
- options: { [index: string]: PlcValue };
subscribable: boolean;
+ options: { [index: string]: PlcValue };
}
export interface PlcBrowseItemArrayInfo {
@@ -42,18 +42,18 @@ export interface PlcBrowseRequest extends PlcRequest {
}
export interface PlcBrowseResponse extends PlcResponse {
- request: PlcBrowseRequest;
queryNames: string[];
+ request: PlcBrowseRequest;
}
export interface PlcDiscoveryItem {
name: string;
attributes: { [index: string]: PlcValue };
- options: { [index: string]: string };
- connectionUrl: string;
- transportUrl: string;
protocolCode: string;
transportCode: string;
+ transportUrl: string;
+ connectionUrl: string;
+ options: { [index: string]: string };
}
export interface PlcDiscoveryRequest extends PlcRequest {
@@ -61,8 +61,8 @@ export interface PlcDiscoveryRequest extends PlcRequest {
export interface PlcDiscoveryResponse extends PlcResponse {
responseCode: PlcResponseCode;
- values: PlcDiscoveryItem[];
request: PlcDiscoveryRequest;
+ values: PlcDiscoveryItem[];
}
export interface PlcConnectionMetadata {
@@ -82,17 +82,16 @@ export interface PlcQuery {
}
export interface PlcTag {
- addressString: string;
- arrayInfo: ArrayInfo[];
plcValueType: PlcValueType;
+ arrayInfo: ArrayInfo[];
+ addressString: string;
}
export interface PlcValue {
bigInteger: number;
- boolean: boolean;
- simple: boolean;
short: number;
length: number;
+ boolean: boolean;
byte: number;
int: number;
long: number;
@@ -107,11 +106,12 @@ export interface PlcValue {
duration: Duration;
date: Date;
keys: string[];
- list: PlcValue[];
- nullable: boolean;
- metaDataNames: string[];
- dateTime: Date;
plcValueType: PlcValueType;
+ dateTime: Date;
+ metaDataNames: string[];
+ nullable: boolean;
+ list: PlcValue[];
+ simple: boolean;
raw: any;
struct: { [index: string]: PlcValue };
}
@@ -136,6 +136,10 @@ export interface TemporalAmount {
export interface Serializable {
}
+export interface Device {
+ id: number;
+}
+
export interface Driver {
code: string;
name: string;
@@ -174,6 +178,14 @@ export class RestApplicationClient<O> {
constructor(protected httpClient: HttpClient<O>) {
}
+ /**
+ * HTTP GET /api/discover/{protocolCode}
+ * Java method: org.apache.plc4x.java.tools.ui.controller.DriverController.discover
+ */
+ discover(protocolCode: string, options?: O): RestResponse<Device[]> {
+ return this.httpClient.request({ method: "GET", url: uriEncoding`api/discover/${protocolCode}`, options: options });
+ }
+
/**
* HTTP GET /api/drivers
* Java method: org.apache.plc4x.java.tools.ui.controller.DriverController.getDriverList
diff --git a/plc4j/tools/ui/frontend/frontend/src/pages/Inspect.tsx b/plc4j/tools/ui/frontend/frontend/src/pages/Inspect.tsx
index e2e533ddee..fb546f8000 100644
--- a/plc4j/tools/ui/frontend/frontend/src/pages/Inspect.tsx
+++ b/plc4j/tools/ui/frontend/frontend/src/pages/Inspect.tsx
@@ -20,19 +20,22 @@ import {TabPanel, TabView} from "primereact/tabview";
import {Splitter, SplitterPanel} from "primereact/splitter";
import {useState} from "react";
import {RestApplicationClient} from "../generated/plc4j-tools-ui-frontend.ts";
-import axios from "axios";
import {TreeItemData} from "../model/TreeItemData.ts";
import {ScrollPanel} from "primereact/scrollpanel";
import NavigationTree from "../components/NavigationTree.tsx";
import PlcConnection from "../components/PlcConnection.tsx";
+import axios from "axios";
export default function Inspect() {
+ const [initialized, setInitialized] = useState(false)
const [driverTreeRoots, setDriverTreeRoots] = useState<TreeItemData[]>([])
const restClient = new RestApplicationClient(axios);
function updateDriverList() {
+ console.log("updateDriverList");
const driverList = restClient.getDriverList();
driverList.then(response => {
+ console.log(response);
let newDriverTreeRoots: TreeItemData[] = [];
response.data.map(driverValue => {
newDriverTreeRoots = [...newDriverTreeRoots, {
@@ -51,7 +54,8 @@ export default function Inspect() {
})
}
- if(driverTreeRoots.length == 0) {
+ if(!initialized) {
+ setInitialized(true)
updateDriverList()
}
diff --git a/plc4j/tools/ui/frontend/pom.xml b/plc4j/tools/ui/frontend/pom.xml
index 68c50a5c6d..d015b8a321 100644
--- a/plc4j/tools/ui/frontend/pom.xml
+++ b/plc4j/tools/ui/frontend/pom.xml
@@ -45,6 +45,7 @@
<goal>generate</goal>
</goals>
<configuration>
+ <skip>true</skip>
<classes>
<!-- These are the PLC4J API types -->
<class>org.apache.plc4x.java.api.messages.PlcBrowseItem</class>
diff --git a/plc4j/tools/ui/pom.xml b/plc4j/tools/ui/pom.xml
index 33630e86a6..0f27bb0715 100644
--- a/plc4j/tools/ui/pom.xml
+++ b/plc4j/tools/ui/pom.xml
@@ -35,6 +35,7 @@
<properties>
<project.build.outputTimestamp>2023-11-02T07:23:09Z</project.build.outputTimestamp>
+ <spring-boot.version>3.2.1</spring-boot.version>
</properties>
<modules>
@@ -43,4 +44,32 @@
<module>frontend</module>
</modules>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-dependencies</artifactId>
+ <version>${spring-boot.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jakarta.annotation</groupId>
+ <artifactId>jakarta.annotation-api</artifactId>
+ <version>2.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.aspectj</groupId>
+ <artifactId>aspectjweaver</artifactId>
+ <version>1.9.20.1</version>
+ </dependency>
+ <dependency>
+ <groupId>io.projectreactor</groupId>
+ <artifactId>reactor-core</artifactId>
+ <version>3.6.1</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
</project>
\ No newline at end of file