|
28 | 28 | import java.util.Optional;
|
29 | 29 | import java.util.Random;
|
30 | 30 | import java.util.Set;
|
31 |
| -import java.util.concurrent.CompletableFuture; |
32 |
| -import java.util.concurrent.ConcurrentHashMap; |
33 |
| -import java.util.concurrent.ExecutorService; |
34 |
| -import java.util.concurrent.ScheduledExecutorService; |
| 31 | +import java.util.concurrent.*; |
35 | 32 | import java.util.concurrent.atomic.AtomicLong;
|
36 | 33 | import java.util.stream.Collectors;
|
37 | 34 | import java.util.stream.Stream;
|
@@ -135,6 +132,8 @@ public class OpcUaServer extends AbstractServiceHandler {
|
135 | 132 |
|
136 | 133 | private final ServerDiagnosticsSummary diagnosticsSummary = new ServerDiagnosticsSummary(this);
|
137 | 134 |
|
| 135 | + private final List<EndpointConfig> boundEndpoints = new CopyOnWriteArrayList<>(); |
| 136 | + |
138 | 137 | /**
|
139 | 138 | * SecureChannel id sequence, starting at a random value in [1..{@link Integer#MAX_VALUE}], and
|
140 | 139 | * wrapping back to 1 after {@link UInteger#MAX_VALUE}.
|
@@ -257,15 +256,29 @@ public CompletableFuture<OpcUaServer> startup() {
|
257 | 256 | transport.bind(applicationContext, bindAddress);
|
258 | 257 |
|
259 | 258 | transports.put(transportProfile, transport);
|
| 259 | + |
| 260 | + boundEndpoints.add(endpoint); |
260 | 261 | } catch (Exception e) {
|
261 |
| - throw new RuntimeException(e); |
| 262 | + logger.warn( |
| 263 | + "Failed to bind endpoint {} to {}:{} [{}/{}]", |
| 264 | + endpoint.getEndpointUrl(), |
| 265 | + endpoint.getBindAddress(), |
| 266 | + endpoint.getBindPort(), |
| 267 | + endpoint.getSecurityPolicy(), |
| 268 | + endpoint.getSecurityMode(), |
| 269 | + e); |
262 | 270 | }
|
263 | 271 | } else {
|
264 | 272 | logger.warn("No OpcServerTransport for TransportProfile: {}", transportProfile);
|
265 | 273 | }
|
266 | 274 | });
|
267 | 275 |
|
268 |
| - return CompletableFuture.completedFuture(this); |
| 276 | + if (boundEndpoints.isEmpty()) { |
| 277 | + return CompletableFuture.failedFuture( |
| 278 | + new UaException(StatusCodes.Bad_ConfigurationError, "No endpoints bound")); |
| 279 | + } else { |
| 280 | + return CompletableFuture.completedFuture(this); |
| 281 | + } |
269 | 282 | }
|
270 | 283 |
|
271 | 284 | public CompletableFuture<OpcUaServer> shutdown() {
|
@@ -458,6 +471,15 @@ public Optional<RoleMapper> getRoleMapper() {
|
458 | 471 | return config.getRoleMapper();
|
459 | 472 | }
|
460 | 473 |
|
| 474 | + /** |
| 475 | + * Get the {@link EndpointConfig}s that were successfully bound during {@link #startup()}. |
| 476 | + * |
| 477 | + * @return the {@link EndpointConfig}s that were successfully bound during {@link #startup()}. |
| 478 | + */ |
| 479 | + public List<EndpointConfig> getBoundEndpoints() { |
| 480 | + return List.copyOf(boundEndpoints); |
| 481 | + } |
| 482 | + |
461 | 483 | private class ServerApplicationContextImpl implements ServerApplicationContext {
|
462 | 484 |
|
463 | 485 | @Override
|
|
0 commit comments