blob: 1acd8debfc3dcb6581a11c88238c38362bc0a055 [file] [log] [blame]
/*
* 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.camel.component.milo.call;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import org.eclipse.milo.opcua.sdk.core.Reference;
import org.eclipse.milo.opcua.sdk.server.OpcUaServer;
import org.eclipse.milo.opcua.sdk.server.api.AccessContext;
import org.eclipse.milo.opcua.sdk.server.api.DataItem;
import org.eclipse.milo.opcua.sdk.server.api.MethodInvocationHandler;
import org.eclipse.milo.opcua.sdk.server.api.MonitoredItem;
import org.eclipse.milo.opcua.sdk.server.api.Namespace;
import org.eclipse.milo.opcua.sdk.server.api.ServerNodeMap;
import org.eclipse.milo.opcua.sdk.server.model.nodes.objects.FolderNode;
import org.eclipse.milo.opcua.sdk.server.nodes.AttributeContext;
import org.eclipse.milo.opcua.sdk.server.nodes.ServerNode;
import org.eclipse.milo.opcua.sdk.server.nodes.UaFolderNode;
import org.eclipse.milo.opcua.sdk.server.nodes.UaMethodNode;
import org.eclipse.milo.opcua.sdk.server.util.SubscriptionModel;
import org.eclipse.milo.opcua.stack.core.Identifiers;
import org.eclipse.milo.opcua.stack.core.StatusCodes;
import org.eclipse.milo.opcua.stack.core.UaException;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName;
import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId;
import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue;
import static java.util.stream.Collectors.toList;
public class MockNamespace implements Namespace {
public static final int FOLDER_ID = 1;
public static final String URI = "urn:mock:namespace";
private final UShort index;
private final ServerNodeMap nodeMap;
private final SubscriptionModel subscriptionModel;
public MockNamespace(final UShort index, final OpcUaServer server, List<UaMethodNode> methods) {
this.index = index;
this.nodeMap = server.getNodeMap();
this.subscriptionModel = new SubscriptionModel(server, this);
registerItems(methods);
}
private void registerItems(List<UaMethodNode> methods) {
// create a folder
final UaFolderNode folder = new UaFolderNode(this.nodeMap, new NodeId(this.index, FOLDER_ID), new QualifiedName(this.index, "FooBarFolder"),
LocalizedText.english("Foo Bar Folder"));
// add our folder to the objects folder
this.nodeMap.getNode(Identifiers.ObjectsFolder).ifPresent(node -> {
((FolderNode)node).addComponent(folder);
});
// add method calls
methods.forEach(folder::addComponent);
}
// default method implementations follow
@Override
public void read(final ReadContext context, final Double maxAge, final TimestampsToReturn timestamps, final List<ReadValueId> readValueIds) {
final List<DataValue> results = new ArrayList<>(readValueIds.size());
for (final ReadValueId id : readValueIds) {
final ServerNode node = this.nodeMap.get(id.getNodeId());
final DataValue value = node != null ? node.readAttribute(new AttributeContext(context), id.getAttributeId()) : new DataValue(StatusCodes.Bad_NodeIdUnknown);
results.add(value);
}
// report back with result
context.complete(results);
}
@Override
public void write(final WriteContext context, final List<WriteValue> writeValues) {
final List<StatusCode> results = writeValues.stream().map(value -> {
if (this.nodeMap.containsKey(value.getNodeId())) {
return new StatusCode(StatusCodes.Bad_NotWritable);
} else {
return new StatusCode(StatusCodes.Bad_NodeIdUnknown);
}
}).collect(toList());
// report back with result
context.complete(results);
}
@Override
public CompletableFuture<List<Reference>> browse(final AccessContext context, final NodeId nodeId) {
final ServerNode node = this.nodeMap.get(nodeId);
if (node != null) {
return CompletableFuture.completedFuture(node.getReferences());
} else {
final CompletableFuture<List<Reference>> f = new CompletableFuture<>();
f.completeExceptionally(new UaException(StatusCodes.Bad_NodeIdUnknown));
return f;
}
}
@Override
public Optional<MethodInvocationHandler> getInvocationHandler(final NodeId methodId) {
return Optional.ofNullable(this.nodeMap.get(methodId)).filter(n -> n instanceof UaMethodNode).flatMap(n -> {
final UaMethodNode m = (UaMethodNode)n;
return m.getInvocationHandler();
});
}
@Override
public void onDataItemsCreated(final List<DataItem> dataItems) {
this.subscriptionModel.onDataItemsCreated(dataItems);
}
@Override
public void onDataItemsModified(final List<DataItem> dataItems) {
this.subscriptionModel.onDataItemsModified(dataItems);
}
@Override
public void onDataItemsDeleted(final List<DataItem> dataItems) {
this.subscriptionModel.onDataItemsDeleted(dataItems);
}
@Override
public void onMonitoringModeChanged(final List<MonitoredItem> monitoredItems) {
this.subscriptionModel.onMonitoringModeChanged(monitoredItems);
}
@Override
public UShort getNamespaceIndex() {
return this.index;
}
@Override
public String getNamespaceUri() {
return URI;
}
}