Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,18 @@
import org.eclipse.milo.opcua.sdk.server.namespaces.OpcUaNamespace;
import org.eclipse.milo.opcua.sdk.server.namespaces.ServerNamespace;
import org.eclipse.milo.opcua.sdk.server.nodes.factories.EventFactory;
import org.eclipse.milo.opcua.sdk.server.servicesets.AttributeServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.DiscoveryServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.MethodServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.MonitoredItemServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.NodeManagementServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.QueryServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.Service;
import org.eclipse.milo.opcua.sdk.server.servicesets.SessionServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.SubscriptionServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.ViewServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.AccessController;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultAccessController;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultAttributeServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultDiscoveryServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultMethodServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultMonitoredItemServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultNodeManagementServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultQueryServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultSessionServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultSubscriptionServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultViewServiceSet;
import org.eclipse.milo.opcua.sdk.server.subscriptions.Subscription;
import org.eclipse.milo.opcua.sdk.server.typetree.DataTypeTreeBuilder;
import org.eclipse.milo.opcua.sdk.server.typetree.ObjectTypeTreeBuilder;
Expand Down Expand Up @@ -189,6 +189,22 @@ public class OpcUaServer extends AbstractServiceHandler {
private final ServerApplicationContext applicationContext;

public OpcUaServer(OpcUaServerConfig config, OpcServerTransportFactory transportFactory) {
this(config, transportFactory, new ServiceSets() {});
}

/**
* Create an OpcUaServer using the service set implementations supplied by {@code serviceSets}.
*
* @param config the {@link OpcUaServerConfig}.
* @param transportFactory the {@link OpcServerTransportFactory}.
* @param serviceSets the {@link ServiceSets} supplying the service set implementations this
* server uses.
*/
public OpcUaServer(
OpcUaServerConfig config,
OpcServerTransportFactory transportFactory,
ServiceSets serviceSets) {

this.config = config;
this.transportFactory = transportFactory;

Expand Down Expand Up @@ -255,19 +271,31 @@ public ServerTable getServerTable() {
.map(e -> EndpointUtil.getPath(e.getEndpointUrl()))
.distinct();

DiscoveryServiceSet discoveryServiceSet = serviceSets.createDiscoveryServiceSet(this);
AttributeServiceSet attributeServiceSet = serviceSets.createAttributeServiceSet(this);
MethodServiceSet methodServiceSet = serviceSets.createMethodServiceSet(this);
MonitoredItemServiceSet monitoredItemServiceSet =
serviceSets.createMonitoredItemServiceSet(this);
NodeManagementServiceSet nodeManagementServiceSet =
serviceSets.createNodeManagementServiceSet(this);
QueryServiceSet queryServiceSet = serviceSets.createQueryServiceSet(this);
SessionServiceSet sessionServiceSet = serviceSets.createSessionServiceSet(this);
SubscriptionServiceSet subscriptionServiceSet = serviceSets.createSubscriptionServiceSet(this);
ViewServiceSet viewServiceSet = serviceSets.createViewServiceSet(this);

paths.forEach(
path -> {
addServiceSet(path, new DefaultDiscoveryServiceSet(OpcUaServer.this));
addServiceSet(path, discoveryServiceSet);

if (!path.endsWith("/discovery")) {
addServiceSet(path, new DefaultAttributeServiceSet(OpcUaServer.this));
addServiceSet(path, new DefaultMethodServiceSet(OpcUaServer.this));
addServiceSet(path, new DefaultMonitoredItemServiceSet(OpcUaServer.this));
addServiceSet(path, new DefaultNodeManagementServiceSet(OpcUaServer.this));
addServiceSet(path, new DefaultQueryServiceSet());
addServiceSet(path, new DefaultSessionServiceSet(OpcUaServer.this));
addServiceSet(path, new DefaultSubscriptionServiceSet(OpcUaServer.this));
addServiceSet(path, new DefaultViewServiceSet(OpcUaServer.this));
addServiceSet(path, attributeServiceSet);
addServiceSet(path, methodServiceSet);
addServiceSet(path, monitoredItemServiceSet);
addServiceSet(path, nodeManagementServiceSet);
addServiceSet(path, queryServiceSet);
addServiceSet(path, sessionServiceSet);
addServiceSet(path, subscriptionServiceSet);
addServiceSet(path, viewServiceSet);
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2026 the Eclipse Milo Authors
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/

package org.eclipse.milo.opcua.sdk.server;

import org.eclipse.milo.opcua.sdk.server.servicesets.AttributeServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.DiscoveryServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.MethodServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.MonitoredItemServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.NodeManagementServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.QueryServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.SessionServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.SubscriptionServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.ViewServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultAttributeServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultDiscoveryServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultMethodServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultMonitoredItemServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultNodeManagementServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultQueryServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultSessionServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultSubscriptionServiceSet;
import org.eclipse.milo.opcua.sdk.server.servicesets.impl.DefaultViewServiceSet;

/**
* Factories for the service set implementations an {@link OpcUaServer} uses.
*
* <p>Each factory method is invoked once while the server is constructed, and the returned instance
* is registered on every applicable endpoint path: the {@link DiscoveryServiceSet} on all paths,
* the other service sets on all paths not suffixed with "/discovery".
*
* <p>All methods have defaults that return the standard implementations, so an implementation only
* overrides the service sets it replaces:
*
* <pre>{@code
* var server = new OpcUaServer(config, transportFactory, new ServiceSets() {
* @Override
* public DiscoveryServiceSet createDiscoveryServiceSet(OpcUaServer server) {
* return new DefaultDiscoveryServiceSet(server, additionalServersSupplier);
* }
* });
* }</pre>
*/
public interface ServiceSets {

default AttributeServiceSet createAttributeServiceSet(OpcUaServer server) {
return new DefaultAttributeServiceSet(server);
}

default DiscoveryServiceSet createDiscoveryServiceSet(OpcUaServer server) {
return new DefaultDiscoveryServiceSet(server);
}

default MethodServiceSet createMethodServiceSet(OpcUaServer server) {
return new DefaultMethodServiceSet(server);
}

default MonitoredItemServiceSet createMonitoredItemServiceSet(OpcUaServer server) {
return new DefaultMonitoredItemServiceSet(server);
}

default NodeManagementServiceSet createNodeManagementServiceSet(OpcUaServer server) {
return new DefaultNodeManagementServiceSet(server);
}

default QueryServiceSet createQueryServiceSet(OpcUaServer server) {
return new DefaultQueryServiceSet();
}

default SessionServiceSet createSessionServiceSet(OpcUaServer server) {
return new DefaultSessionServiceSet(server);
}

default SubscriptionServiceSet createSubscriptionServiceSet(OpcUaServer server) {
return new DefaultSubscriptionServiceSet(server);
}

default ViewServiceSet createViewServiceSet(OpcUaServer server) {
return new DefaultViewServiceSet(server);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
import static java.util.stream.Collectors.toList;
import static org.eclipse.milo.opcua.sdk.server.servicesets.AbstractServiceSet.createResponseHeader;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
import org.eclipse.milo.opcua.sdk.server.EndpointConfig;
import org.eclipse.milo.opcua.sdk.server.OpcUaServer;
import org.eclipse.milo.opcua.sdk.server.servicesets.DiscoveryServiceSet;
Expand Down Expand Up @@ -44,9 +46,32 @@ public class DefaultDiscoveryServiceSet implements DiscoveryServiceSet {
private final Logger logger = LoggerFactory.getLogger(getClass());

private final OpcUaServer server;
private final Supplier<List<ApplicationDescription>> additionalServers;

public DefaultDiscoveryServiceSet(OpcUaServer server) {
this(server, List::of);
}

/**
* Create a DefaultDiscoveryServiceSet that includes additional servers in the results of the
* FindServers service.
*
* <p>The supplier is invoked each time the FindServers service is invoked, and may return
* different results over time. It must not include the ApplicationDescription of {@code server}
* itself; that is always included.
*
* <p>This is intended for use by servers that know of other servers they should advertise, e.g.
* the other members of a non-transparent redundant server set.
*
* @param server the {@link OpcUaServer} this service set belongs to.
* @param additionalServers a supplier of additional {@link ApplicationDescription}s to include in
* the results of the FindServers service.
*/
public DefaultDiscoveryServiceSet(
OpcUaServer server, Supplier<List<ApplicationDescription>> additionalServers) {

this.server = server;
this.additionalServers = additionalServers;
}

@Override
Expand Down Expand Up @@ -94,8 +119,9 @@ public FindServersResponse onFindServers(
? List.of(request.getServerUris())
: Collections.emptyList();

List<ApplicationDescription> applicationDescriptions =
List.of(getFilteredApplicationDescription(request.getEndpointUrl()));
List<ApplicationDescription> applicationDescriptions = new ArrayList<>();
applicationDescriptions.add(getFilteredApplicationDescription(request.getEndpointUrl()));
applicationDescriptions.addAll(additionalServers.get());

applicationDescriptions =
applicationDescriptions.stream().filter(ad -> filterServerUris(ad, serverUris)).toList();
Expand Down
Loading
Loading