blob: bd828a6bb74e506acdeff86399253f3573f33a46 [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.client;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import org.apache.camel.component.milo.client.internal.SubscriptionManager;
import org.eclipse.milo.opcua.stack.core.Stack;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
import org.eclipse.milo.opcua.stack.core.types.builtin.Variant;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.structured.CallMethodResult;
import static java.util.Objects.requireNonNull;
public class MiloClientConnection implements AutoCloseable {
private final MiloClientConfiguration configuration;
private SubscriptionManager manager;
private boolean initialized;
public MiloClientConnection(final MiloClientConfiguration configuration) {
requireNonNull(configuration);
// make a copy since the configuration is mutable
this.configuration = configuration.clone();
}
public MiloClientConfiguration getConfiguration() {
return configuration;
}
protected void init() throws Exception {
this.manager = new SubscriptionManager(this.configuration, Stack.sharedScheduledExecutor(), 10_000);
}
@Override
public void close() throws Exception {
if (this.manager != null) {
this.manager.dispose();
this.manager = null;
}
}
protected synchronized void checkInit() {
if (this.initialized) {
return;
}
try {
init();
} catch (final Exception e) {
throw new RuntimeException(e);
}
this.initialized = true;
}
@FunctionalInterface
public interface MonitorHandle {
void unregister();
}
public MonitorHandle monitorValue(final ExpandedNodeId nodeId, Double samplingInterval, final Consumer<DataValue> valueConsumer) {
requireNonNull(configuration);
requireNonNull(valueConsumer);
checkInit();
final UInteger handle = this.manager.registerItem(nodeId, samplingInterval, valueConsumer);
return () -> MiloClientConnection.this.manager.unregisterItem(handle);
}
public String getConnectionId() {
return this.configuration.toCacheId();
}
public CompletableFuture<?> writeValue(final ExpandedNodeId nodeId, final Object value) {
checkInit();
return this.manager.write(nodeId, mapWriteValue(value));
}
public CompletableFuture<CallMethodResult> call(final ExpandedNodeId nodeId, final ExpandedNodeId methodId, final Object value) {
checkInit();
return this.manager.call(nodeId, methodId, mapCallValue(value));
}
/**
* Map the incoming value to some value callable to the milo client
*
* @param value the incoming value
* @return the outgoing call request
*/
private Variant[] mapCallValue(final Object value) {
if (value == null) {
return new Variant[0];
}
if (value instanceof Variant[]) {
return (Variant[])value;
}
if (value instanceof Variant) {
return new Variant[] {(Variant)value};
}
return new Variant[] {new Variant(value)};
}
/**
* Map the incoming value to some value writable to the milo client
*
* @param value the incoming value
* @return the outgoing value
*/
private DataValue mapWriteValue(final Object value) {
if (value instanceof DataValue) {
return (DataValue)value;
}
if (value instanceof Variant) {
return new DataValue((Variant)value, StatusCode.GOOD, null, null);
}
return new DataValue(new Variant(value), StatusCode.GOOD, null, null);
}
}