Skip to content
Snippets Groups Projects
Commit 8eb49cfd authored by Guillaume PICHON's avatar Guillaume PICHON
Browse files

End of structuring. First complete version before tests.

parent 0793677d
No related branches found
No related tags found
No related merge requests found
Showing
with 673 additions and 402 deletions
......@@ -10,13 +10,32 @@ import fr.soleil.opcuaproxy.subscriber.OpcUaSubscriber;
public class OpcUaProxy {
public static OpcUaConnector connector = null;
private static Object connectorLocker = null;
static {
connectorLocker = new Object();
}
/**
* Wait for the connector and return it when ready.
*
* @return
* @throws InterruptedException
*/
public static OpcUaConnector waitAndGetConnector() throws InterruptedException {
OpcUaConnector connector = null;
synchronized (connectorLocker) {
if (OpcUaProxy.connector == null) {
connectorLocker.wait();
}
connector = OpcUaProxy.connector;
}
return connector;
}
/**
* Return the current connector.
*
* @return
*/
public static OpcUaConnector getConnector() {
......@@ -29,6 +48,7 @@ public class OpcUaProxy {
/**
* Set the given connector if none is already sets.
*
* @param connector The connector to set.
* @return True if the connector is set with the given one.
*/
......@@ -37,6 +57,7 @@ public class OpcUaProxy {
synchronized (connectorLocker) {
if (OpcUaProxy.connector == null) {
OpcUaProxy.connector = connector;
connectorLocker.notifyAll();
done = true;
}
}
......@@ -44,7 +65,8 @@ public class OpcUaProxy {
}
/**
* Unset the connector if, and only if, the current connector is the one given in parameter.
* Unset the connector if, and only if, the current connector is the one given
* in parameter.
*
* @param connector The connector to unset.
* @return true if the connector is unset. False otherwise.
......
package fr.soleil.opcuaproxy.attributes;
import fr.esrf.Tango.DevFailed;
public interface IOpcUaNodeWriter {
/**
* Write a value to a given node.
*
* @param nodeToWrite The node to write on.
* @param value The value to write. Must be in the correct class.
* @return True if the value has been written.
* @throws DevFailed
*/
boolean writeNode(OpcUaAttributeReference nodeToWrite, Object value) throws DevFailed;
}
\ No newline at end of file
......@@ -2,6 +2,7 @@ package fr.soleil.opcuaproxy.attributes;
import java.util.Set;
import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -12,13 +13,13 @@ import org.tango.server.attribute.AttributeValue;
import org.tango.server.attribute.IAttributeBehavior;
import org.tango.server.events.EventType;
import fr.esrf.Tango.AttrWriteType;
import fr.esrf.Tango.DevFailed;
import fr.soleil.opcuaproxy.connector.OpcUaProxyClient;
/**
* A sample attribute
*
* @author ABEILLE
* @author Guillaume Pichon
*
*/
public class OpcUaAttribute implements IAttributeBehavior, Comparable<OpcUaAttribute> {
......@@ -26,17 +27,17 @@ public class OpcUaAttribute implements IAttributeBehavior, Comparable<OpcUaAttri
private AttributeValue attrVal;
private AttributeConfiguration configuration;
private OpcUaProxyClient tangoOPCUAClient;
private IOpcUaNodeWriter nodeWriter;
private OpcUaAttributeParameters parameters;
private UInteger subscriptionId;
private Class<? extends Object> opcuaClass;
public OpcUaAttribute(AttributeValue firstValue, AttributeConfiguration configuration, OpcUaProxyClient tangoOPCUAClient,
public OpcUaAttribute(AttributeValue firstValue, AttributeConfiguration configuration, IOpcUaNodeWriter nodeWriter,
OpcUaAttributeParameters parameters, UInteger subscriptionId, Class<? extends Object> opcuaClass) {
this.attrVal = firstValue;
this.configuration = configuration;
this.tangoOPCUAClient = tangoOPCUAClient;
this.nodeWriter = nodeWriter;
this.parameters = parameters;
this.subscriptionId = subscriptionId;
this.opcuaClass = opcuaClass;
......@@ -75,7 +76,7 @@ public class OpcUaAttribute implements IAttributeBehavior, Comparable<OpcUaAttri
Object tangoValue = value.getValue();
Object opcuaValue = OpcUaTangoUtils.getOpcuaValue(tangoValue, opcuaClass);
for (OpcUaAttributeReference writeRef : parameters.getWriteNodes()) {
tangoOPCUAClient.writeNode(writeRef, opcuaValue);
nodeWriter.writeNode(writeRef, opcuaValue);
}
}
}
......@@ -149,4 +150,62 @@ public class OpcUaAttribute implements IAttributeBehavior, Comparable<OpcUaAttri
return false;
}
public static OpcUaAttribute buildAttribute(OpcUaAttributeParameters parameters, DateTime firstDataDateTime,
Object firstValue, Class<? extends Object> valueClass, UInteger subscriptionId, IOpcUaNodeWriter nodeWriter)
throws DevFailed {
final AttributeConfiguration config = new AttributeConfiguration();
config.setName(parameters.getAttributeName());
config.getAttributeProperties().setLabel(parameters.getAttributeLabel());
StringBuilder descBuilder = new StringBuilder();
descBuilder.append("Subscription id = ");
descBuilder.append(subscriptionId);
descBuilder.append('\n');
descBuilder.append("Value type = ");
String className = "null";
if (firstValue != null) {
if (firstValue.getClass().isArray()) {
className = "Array of " + firstValue.getClass().getComponentType().getSimpleName();
} else {
className = firstValue.getClass().getSimpleName();
}
}
descBuilder.append(className);
descBuilder.append('\n');
descBuilder.append("Read value = ");
descBuilder.append(parameters.getReadNode().toString());
descBuilder.append('\n');
if (!parameters.getWriteNodes().isEmpty()) {
descBuilder.append("Write values:\n");
for (OpcUaAttributeReference writePart : parameters.getWriteNodes()) {
descBuilder.append('\t');
descBuilder.append(writePart.toString());
descBuilder.append('\n');
}
}
// Note for refactoring : create a configuration builder.
config.getAttributeProperties().setDescription(descBuilder.toString());
config.setType(OpcUaTangoUtils.getTangoClass(firstValue));
if (!parameters.getWriteNodes().isEmpty()) {
config.setWritable(AttrWriteType.READ_WRITE);
} else {
config.setWritable(AttrWriteType.READ);
}
// Activation of events.
config.setPushArchiveEvent(parameters.isTangoEventActivated(EventType.ARCHIVE_EVENT));
config.setPushChangeEvent(parameters.isTangoEventActivated(EventType.CHANGE_EVENT));
config.setPushDataReady(parameters.isTangoEventActivated(EventType.DATA_READY_EVENT));
AttributeValue attrValue = null;
try {
attrValue = new AttributeValue(OpcUaTangoUtils.getTangoValue(firstValue));
attrValue.setTime(firstDataDateTime.getJavaDate().getTime());
} catch (DevFailed e) {
logger.error("Attribute value error {}. value={} ", parameters.getReadNode().toString(), firstValue);
}
OpcUaAttribute attribute = new OpcUaAttribute(attrValue, config, nodeWriter, parameters, subscriptionId,
valueClass);
return attribute;
}
}
......@@ -20,7 +20,7 @@ import fr.soleil.opcuaproxy.OpcUaProxyException;
*
* @author Patrick Madela
*/
public abstract class OpcUaClientFactory {
abstract class OpcUaClientFactory {
/** The OPC-UA client application URI */
private final String applicationUri;
......
......@@ -30,7 +30,7 @@ import fr.soleil.opcuaproxy.connector.certificats.KeyStoreLoader;
*
* @author Patrick Madela
*/
public class OpcUaClientSecurityCertificateFactory extends OpcUaClientFactory {
class OpcUaClientSecurityCertificateFactory extends OpcUaClientFactory {
/** The security policy to use */
public static final SecurityPolicy SECURITY_POLICY = SecurityPolicy.Basic256Sha256;
......
......@@ -11,7 +11,7 @@ import fr.soleil.opcuaproxy.OpcUaProxyException;
*
* @author Patrick Madela
*/
public class OpcUaClientSecurityNoneFactory extends OpcUaClientFactory {
class OpcUaClientSecurityNoneFactory extends OpcUaClientFactory {
/** The security policy to use */
public static final SecurityPolicy SECURITY_POLICY = SecurityPolicy.None;
......
......@@ -105,7 +105,7 @@ public class OpcUaConnector extends AOpcUaSubscriber {
@Attribute(name = "asyncReplyResult")
private String[] asyncReplyResultAttribute = { "" };
private OpcUaProxyClient tangoOPCUAClient;
private OpcUaProxyClient opcUaProxyClient;
private Thread browseAllNodesThread = null;
......@@ -117,37 +117,31 @@ public class OpcUaConnector extends AOpcUaSubscriber {
* @throws DevFailed
*/
@Init
@StateMachine(endState = DeviceState.ON)
public void init() throws DevFailed {
setStatus("Init in progress");
setState(DeviceState.INIT);
logger.debug("opcuaURL value = {}", opcuaURL);
// logger.debug("deviceProperties value = {}", deviceProperties);
dynamicManager.addAttribute(new LogAttribute(1000, logger, LoggerFactory.getLogger(OpcUaConnector.class),
LoggerFactory.getLogger(OpcUaAttribute.class), LoggerFactory.getLogger(OpcUaProxyClient.class)));
browseAllNodesThread = null;
boolean registerOk = OpcUaProxy.setConnector(this);
if (!registerOk) {
// Another connector is running.
}
String[] asyncReplyResultAttribute = { "" };
this.asyncReplyResultAttribute = asyncReplyResultAttribute;
this.diagnosticAttributes = null;
OpcUaClientFactory opcuaClientFactory = getOpcuaClientFactory(deviceManager.getName(), opcuaURL,
requestTimeout);
this.tangoOPCUAClient = new OpcUaProxyClient(opcuaClientFactory);
this.tangoOPCUAClient.connect(this::setStateStatus);
this.opcUaProxyClient = new OpcUaProxyClient(opcuaClientFactory);
this.opcUaProxyClient.connect(this::setStateStatus);
if (createDiagnosticAttributes) {
createDiagnosticAttributes();
}
String sessionName = this.tangoOPCUAClient.getSessionName();
String sessionId = this.tangoOPCUAClient.getSessionIdString();
String sessionName = this.opcUaProxyClient.getSessionName();
String sessionId = this.opcUaProxyClient.getSessionIdString();
StringBuilder statusBuilder = new StringBuilder();
statusBuilder.append("Init done.\n");
statusBuilder.append("Session name = ");
if (sessionName != null) {
statusBuilder.append(sessionName);
......@@ -163,12 +157,18 @@ public class OpcUaConnector extends AOpcUaSubscriber {
}
logger.info(statusBuilder.toString());
if (getStatus().equals("Init in progress")) {
setStatus(statusBuilder.toString());
} else {
setStatus(getStatus() + "\n" + statusBuilder.toString());
boolean registerOk = OpcUaProxy.setConnector(this);
if (!registerOk) {
// Another connector is running.
delete();
throw DevFailedUtils.newDevFailed(sessionId);
}
if (getState() == DeviceState.INIT) {
setState(DeviceState.ON);
}
logger.debug("init done for device {} ", deviceManager.getName());
}
......@@ -186,7 +186,7 @@ public class OpcUaConnector extends AOpcUaSubscriber {
super.deleteAttributes();
String[] asyncReplyResultAttribute = { "" };
this.asyncReplyResultAttribute = asyncReplyResultAttribute;
this.tangoOPCUAClient.disconnect();
this.opcUaProxyClient.disconnect();
this.browseAllNodesThread = null;
removeDiagnosticAttributes();
}
......@@ -196,7 +196,7 @@ public class OpcUaConnector extends AOpcUaSubscriber {
if (this.diagnosticAttributes != null) {
removeDiagnosticAttributes();
}
NodeId sessionNodeId = this.tangoOPCUAClient.getSessionId();
NodeId sessionNodeId = this.opcUaProxyClient.getSessionId();
OpcUaSimpleNode sessionSimpleNodeId = new OpcUaSimpleNode(sessionNodeId);
SubscriptionResult result = createOPCUAAttributesByBrowsing(sessionSimpleNodeId, false,
requestedPublishingIntervalForDiagnostic, samplingIntervalForSubscriptionForDiagnostic,
......@@ -221,7 +221,7 @@ public class OpcUaConnector extends AOpcUaSubscriber {
@Override
public void run() {
try {
String[] allNodes = OpcUaConnector.this.tangoOPCUAClient.browseNode(Identifiers.ObjectsFolder);
String[] allNodes = OpcUaConnector.this.opcUaProxyClient.browseNode(Identifiers.ObjectsFolder);
receivedAsyncReply(allNodes);
} catch (DevFailed e) {
logger.error("Browse all nodes failed.", e);
......@@ -246,7 +246,7 @@ public class OpcUaConnector extends AOpcUaSubscriber {
double requestedPublishingInterval) throws DevFailed {
SubscriptionResult result = null;
if (!parametersList.isEmpty()) {
result = this.tangoOPCUAClient.subscribeTo(parametersList, requestedPublishingInterval,
result = this.opcUaProxyClient.subscribeTo(parametersList, requestedPublishingInterval,
this::attributeValueUpdate);
}
return result;
......@@ -257,7 +257,7 @@ public class OpcUaConnector extends AOpcUaSubscriber {
throws DevFailed {
List<SubscriptionResult> resultList = new ArrayList<>(nodesToBrowse.size());
for (OpcUaSimpleNode toBrowse : nodesToBrowse) {
SubscriptionResult browsedAttrResult = this.tangoOPCUAClient.subscribeToLeafs(toBrowse, activatedEvents,
SubscriptionResult browsedAttrResult = this.opcUaProxyClient.subscribeToLeafs(toBrowse, activatedEvents,
write, requestedPublishingInterval, samplingInterval, this::attributeValueUpdate);
if (browsedAttrResult != null && browsedAttrResult.getSubscriptionId() != null) {
resultList.add(browsedAttrResult);
......@@ -268,13 +268,13 @@ public class OpcUaConnector extends AOpcUaSubscriber {
private void unsubscribe(UInteger subId) throws DevFailed {
removeAttributeForSubscription(subId);
tangoOPCUAClient.unsubscribeTo(subId);
opcUaProxyClient.unsubscribeTo(subId);
}
public SubscriptionResult createOPCUAAttributesByBrowsing(final OpcUaSimpleNode nodeToBrowse, boolean write,
double requestedPublishingInterval, double samplingInterval, Set<EventType> activatedEvents)
throws DevFailed {
SubscriptionResult result = this.tangoOPCUAClient.subscribeToLeafs(nodeToBrowse, activatedEvents, write,
SubscriptionResult result = this.opcUaProxyClient.subscribeToLeafs(nodeToBrowse, activatedEvents, write,
requestedPublishingInterval, samplingInterval, this::attributeValueUpdate);
return result;
}
......@@ -353,6 +353,14 @@ public class OpcUaConnector extends AOpcUaSubscriber {
}
}
public void setRequestedPublishingIntervalForDiagnostic(double requestedPublishingIntervalForDiagnostic) {
this.requestedPublishingIntervalForDiagnostic = requestedPublishingIntervalForDiagnostic;
}
public void setSamplingIntervalForSubscriptionForDiagnostic(double samplingIntervalForSubscriptionForDiagnostic) {
this.samplingIntervalForSubscriptionForDiagnostic = samplingIntervalForSubscriptionForDiagnostic;
}
public void setState(final DeviceState state) {
this.state = state;
}
......
package fr.soleil.opcuaproxy.connector;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Map.Entry;
import org.eclipse.milo.opcua.binaryschema.Struct;
import org.eclipse.milo.opcua.binaryschema.Struct.Builder;
import org.eclipse.milo.opcua.binaryschema.Struct.Member;
import org.eclipse.milo.opcua.stack.core.serialization.SerializationContext;
import org.eclipse.milo.opcua.stack.core.types.OpcUaDefaultBinaryEncoding;
import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import fr.esrf.Tango.DevFailed;
import fr.soleil.opcuaproxy.attributes.IOpcUaNodeWriter;
import fr.soleil.opcuaproxy.attributes.MemberHierachy;
import fr.soleil.opcuaproxy.attributes.OpcUaAttribute;
import fr.soleil.opcuaproxy.attributes.OpcUaAttributeParameters;
import fr.soleil.opcuaproxy.attributes.OpcUaAttributeReference;
import fr.soleil.opcuaproxy.attributes.OpcUaSimpleNode;
import fr.soleil.opcuaproxy.attributes.OpcUaTangoUtils;
class OpcUaStructUtils {
private SerializationContext serializationContext;
public OpcUaStructUtils(SerializationContext serializationContext) {
super();
this.serializationContext = serializationContext;
}
public Map<OpcUaAttributeReference, OpcUaAttribute> getAttrRefForStruct(OpcUaAttributeParameters parameters,
DateTime firstDataDateTime, Struct struct, UInteger subscriptionId, IOpcUaNodeWriter writer)
throws DevFailed {
return getAttrRefForStruct(parameters, firstDataDateTime, struct, subscriptionId, writer, null);
}
public Map<OpcUaAttributeReference, OpcUaAttribute> getAttrRefForStruct(OpcUaAttributeParameters parameters,
DateTime firstDataDateTime, Struct struct, UInteger subscriptionId, IOpcUaNodeWriter writer,
MemberHierachy parentReference) throws DevFailed {
OpcUaSimpleNode node = parameters.getReadNode().getNode();
Map<OpcUaAttributeReference, OpcUaAttribute> result = new TreeMap<>();
for (Member member : struct.getMembers().values()) {
MemberHierachy memberHierarchy = new MemberHierachy(member.getName(), parentReference);
OpcUaAttributeReference attrRef = new OpcUaAttributeReference(node, memberHierarchy);
List<OpcUaAttributeReference> writeRefs = new ArrayList<>(parameters.getWriteNodes().size());
for (OpcUaAttributeReference writeRefOrigin : parameters.getWriteNodes()) {
OpcUaAttributeReference writeRef = new OpcUaAttributeReference(writeRefOrigin.getNode(),
memberHierarchy);
writeRefs.add(writeRef);
}
OpcUaAttributeParameters valueParameters = new OpcUaAttributeParameters(
parameters.getAttributeName() + attrRef.getSubId(),
parameters.getAttributeLabel() + attrRef.getSubId(), parameters.getActivatedEvents(), attrRef,
writeRefs, parameters.getSamplingInterval(), false); // If it's a structure, it's a leaf so it
// cannot be browsed.
Object val = member.getValue();
if (val != null) {
Class<? extends Object> valClass = val.getClass();
// Creating the attribute key
if (val instanceof Struct) {
Map<OpcUaAttributeReference, OpcUaAttribute> subResult = getAttrRefForStruct(valueParameters,
firstDataDateTime, (Struct) val, subscriptionId, writer, memberHierarchy);
result.putAll(subResult);
} else if (val.getClass().isArray() && val.getClass().getComponentType() == ExtensionObject.class) {
int length = Array.getLength(val);
for (int i = 0; i < length; i++) {
Object item = Array.get(val, i);
if (item instanceof ExtensionObject) {
ExtensionObject xo = (ExtensionObject) item;
Object valueObj = xo.decode(serializationContext);
if (valueObj instanceof Struct) {
MemberHierachy memberHierarchyItem = new MemberHierachy(Integer.toString(i),
memberHierarchy);
Struct structItem = (Struct) valueObj;
Map<OpcUaAttributeReference, OpcUaAttribute> subResult = getAttrRefForStruct(parameters,
firstDataDateTime, structItem, subscriptionId, writer, memberHierarchyItem);
result.putAll(subResult);
}
}
}
} else {
// In structures, arrays are not typed. It's corrected here.
boolean empty = false;
if (valClass.isArray()) {
Class<? extends Object> memberClass = valClass.getComponentType();
int length = Array.getLength(val);
if (length > 0) {
if (memberClass == Object.class) {
Object zeroValue = Array.get(val, 0);
memberClass = zeroValue.getClass();
valClass = Array.newInstance(memberClass, 0).getClass();
}
} else {
empty = true;
}
}
// Creating the attribute key.
if (!empty) {
OpcUaAttribute opcuaAttribute = OpcUaAttribute.buildAttribute(valueParameters,
firstDataDateTime, val, valClass, subscriptionId, writer);
result.put(attrRef, opcuaAttribute);
}
}
}
}
return result;
}
public void putAllAttrRefForStruct(Map<OpcUaAttributeReference, Set<OpcUaAttribute>> attributes, ExtensionObject xo,
OpcUaAttributeParameters parameters, DateTime firstDataDateTime, UInteger subscriptionId,
IOpcUaNodeWriter writer, MemberHierachy memberHierarchy) throws DevFailed {
Object valueObj = xo.decode(serializationContext);
if (valueObj instanceof Struct) {
Struct struct = (Struct) valueObj;
Map<OpcUaAttributeReference, OpcUaAttribute> structRes = getAttrRefForStruct(parameters, firstDataDateTime,
struct, subscriptionId, writer, memberHierarchy);
for (Entry<OpcUaAttributeReference, OpcUaAttribute> attrRefForStrucEntry : structRes.entrySet()) {
OpcUaAttributeReference attrRef = attrRefForStrucEntry.getKey();
OpcUaAttribute attribute = attrRefForStrucEntry.getValue();
Set<OpcUaAttribute> attrList = attributes.get(attrRef);
if (attrList == null) {
attrList = new TreeSet<>();
attributes.put(attrRef, attrList);
}
attrList.add(attribute);
}
}
}
public List<String> readStructure(ExtensionObject xo) {
List<String> resultsList = new ArrayList<>();
Object valueObj = xo.decode(serializationContext);
if (valueObj instanceof Struct) {
Struct struct = (Struct) valueObj;
resultsList.addAll(browseStruct("", struct));
}
return resultsList;
}
/**
*
* @param indent Indentation to add at the beginning.
* @param struct The structure to browse.
* @return A list of strings representing the values.
*/
private static List<String> browseStruct(String indent, Struct struct) {
List<String> result = new LinkedList<>();
for (Entry<String, Member> memberEntry : struct.getMembers().entrySet()) {
StringBuilder strBldr = new StringBuilder();
strBldr.append(indent);
strBldr.append(memberEntry.getKey());
strBldr.append(": ");
Object val = memberEntry.getValue().getValue();
Class<? extends Object> valClass = val.getClass();
if (valClass.isArray()) {
// Convert an array of objects into a typed array.
strBldr.append("[");
int length = Array.getLength(val);
Object valArray = null;
if (valClass.getComponentType() == Object.class) {
Object zeroValue = Array.get(val, 0);
valArray = Array.newInstance(zeroValue.getClass(), length);
} else {
valArray = Array.newInstance(valClass.getComponentType(), length);
}
for (int i = 0; i < length; i++) {
Object iValue = Array.get(val, i);
if (i != 0) {
strBldr.append(", ");
}
strBldr.append(iValue.toString());
Array.set(valArray, i, iValue);
}
strBldr.append("]");
result.add(strBldr.toString());
} else if (val instanceof Struct) {
result.add(strBldr.toString());
Struct valStruct = (Struct) val;
result.addAll(browseStruct("\t" + indent, valStruct));
} else {
strBldr.append(val.toString());
result.add(strBldr.toString());
}
}
return result;
}
public ExtensionObject getUpdatedStruct(ExtensionObject toModified, final OpcUaAttributeReference nodeToWrite, final Object value) throws DevFailed {
Object valueObj = toModified.decode(serializationContext);
ExtensionObject modifiedXo = null;
if (valueObj instanceof Struct) {
Struct struct = (Struct) valueObj;
Struct structModifed = updateStruct(struct, nodeToWrite.getNodeMember(), value);
modifiedXo = ExtensionObject.encode(serializationContext,
structModifed, toModified.getEncodingId(), OpcUaDefaultBinaryEncoding.getInstance());
}
return modifiedXo;
}
private static Struct updateStruct(Struct struct, MemberHierachy memberHierarchy, final Object value) {
List<MemberHierachy> hierachy = new LinkedList<>();
MemberHierachy mh = memberHierarchy;
while (mh != null && mh.getParentMember() != null) {
hierachy.add(0, mh);
mh = mh.getParentMember();
}
Builder structBldr = Struct.builder(struct.getName());
for (String memberName : struct.getMembers().keySet()) {
if (mh == null || !memberName.equals(mh.getMemberName())) {
structBldr.addMember(memberName, struct.getMember(memberName).getValue());
}
}
Member member = struct.getMember(mh.getMemberName());
Object memberVal = member.getValue();
Object newMemberVal = null;
if (memberVal instanceof Struct) {
MemberHierachy parent = null;
MemberHierachy nextHierarchy = null;
for (int i = 0; i < hierachy.size(); i++) {
nextHierarchy = new MemberHierachy(hierachy.get(i).getMemberName(), parent);
parent = nextHierarchy;
}
newMemberVal = updateStruct((Struct) memberVal, nextHierarchy, value);
} else {
newMemberVal = value;
}
structBldr.addMember(mh.getMemberName(), newMemberVal);
return structBldr.build();
}
public Map<OpcUaAttributeReference, Object> buildValueMapForStruct(OpcUaSimpleNode node, ExtensionObject xo) {
Object valueObj = xo.decode(serializationContext);
Map<OpcUaAttributeReference, Object> result = null;
if (valueObj instanceof Struct) {
Struct struct = (Struct) valueObj;
result = buildValueMap(node, struct);
}
return result;
}
private static Map<OpcUaAttributeReference, Object> buildValueMap(OpcUaSimpleNode node, Struct struct) {
return buildValueMap(node, struct, null);
}
private static Map<OpcUaAttributeReference, Object> buildValueMap(OpcUaSimpleNode node, Struct struct,
MemberHierachy parentReference) {
Map<OpcUaAttributeReference, Object> result = new TreeMap<>();
for (Member member : struct.getMembers().values()) {
MemberHierachy memberHierarchy = new MemberHierachy(member.getName(), parentReference);
OpcUaAttributeReference attrRef = new OpcUaAttributeReference(node, memberHierarchy);
Object val = member.getValue();
if (val != null) {
Class<? extends Object> valClass = val.getClass();
// Creating the attribute key
if (val instanceof Struct) {
Map<OpcUaAttributeReference, Object> subResult = buildValueMap(node, (Struct) val, memberHierarchy);
result.putAll(subResult);
} else {
// In structures, arrays are not typed. It's corrected here.
if (valClass.isArray()) {
Class<? extends Object> memberClass = valClass.getComponentType();
if (memberClass == Object.class) {
int length = Array.getLength(val);
if (length > 0) {
Object zeroValue = Array.get(val, 0);
memberClass = zeroValue.getClass();
Object newVal = Array.newInstance(memberClass, length);
valClass = newVal.getClass();
for (int i = 0; i < length; i++) {
Object arrayElement = Array.get(val, i);
Array.set(newVal, i, arrayElement);
}
}
}
}
// Creating the attribute key.
result.put(attrRef, OpcUaTangoUtils.getTangoValue(val));
}
}
}
return result;
}
}
package fr.soleil.opcuaproxy.subscriber;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tango.DeviceState;
import org.tango.server.annotation.Delete;
import org.tango.server.annotation.Device;
import org.tango.server.annotation.DeviceManagement;
import org.tango.server.annotation.DeviceProperty;
import org.tango.server.annotation.DynamicManagement;
import org.tango.server.annotation.Init;
import org.tango.server.annotation.State;
import org.tango.server.annotation.StateMachine;
import org.tango.server.annotation.Status;
import org.tango.server.attribute.log.LogAttribute;
import org.tango.server.device.DeviceManager;
import org.tango.server.dynamic.DynamicManager;
import org.tango.utils.DevFailedUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import fr.esrf.Tango.DevFailed;
import fr.soleil.opcuaproxy.AOpcUaSubscriber;
import fr.soleil.opcuaproxy.OpcUaProxy;
import fr.soleil.opcuaproxy.attributes.OpcUaAttribute;
import fr.soleil.opcuaproxy.attributes.OpcUaAttributeParameters;
import fr.soleil.opcuaproxy.attributes.definition.AttributeDefinition;
import fr.soleil.opcuaproxy.attributes.definition.OpcUaAttributesSubscriptions;
import fr.soleil.opcuaproxy.attributes.definition.Subscription;
import fr.soleil.opcuaproxy.connector.OpcUaConnector;
import fr.soleil.opcuaproxy.connector.SubscriptionResult;
@Device
public class OpcUaSubscriber extends AOpcUaSubscriber {
private static final Logger logger = LoggerFactory.getLogger(OpcUaSubscriber.class);
@DeviceProperty(defaultValue = "", description = "The device configuration in JSON format")
private String subscriptionsJson;
/**
* Manage dynamic attributes and commands
*/
@DynamicManagement
public DynamicManager dynamicManager;
/**
* Manage state of the device
*/
@State
private DeviceState state = DeviceState.OFF;
@Status
private String status = "";
@DeviceManagement
private DeviceManager deviceManager;
public class OpcUaSubscriber {
private OpcUaConnector connector;
/**
* init device
*
* @throws DevFailed
*/
@Init
@StateMachine(endState = DeviceState.ON)
public void init() throws DevFailed {
setStatus("Init in progress.\nWaiting for connector to start and initialize.");
dynamicManager.addAttribute(new LogAttribute(1000, logger, LoggerFactory.getLogger(OpcUaAttribute.class)));
try {
connector = OpcUaProxy.waitAndGetConnector();
} catch (InterruptedException e1) {
logger.error("An error occured will waiting for the connector.", e1);
throw DevFailedUtils.newDevFailed(e1);
}
public OpcUaSubscriber() {
ObjectMapper mapper = new ObjectMapper();
// DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
// mapper.setDateFormat(df);
String jsonInput = "";
OpcUaAttributesSubscriptions attributes = null;
OpcUaAttributesSubscriptions subscriptions = null;
if (subscriptionsJson != null && !subscriptionsJson.isEmpty()) {
try {
attributes = mapper.readValue(jsonInput, OpcUaAttributesSubscriptions.class);
attributes.toString();
subscriptions = mapper.readValue(subscriptionsJson, OpcUaAttributesSubscriptions.class);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.error("Parsing error for device " + deviceManager.getName(), e);
throw DevFailedUtils.newDevFailed(e);
}
}
List<SubscriptionResult> subscriptionResults = new ArrayList<>(subscriptions.getSubscriptions().size());
for (Subscription subscription : subscriptions.getSubscriptions()) {
List<OpcUaAttributeParameters> parametersList = new ArrayList<>(subscription.getAttributes().size());
for (AttributeDefinition attrDef : subscription.getAttributes()) {
OpcUaAttributeParameters parameters = new OpcUaAttributeParameters(attrDef,
subscriptions.getDefaultType(), subscriptions.getDefaultNamespaceIndex(),
subscriptions.getDefaultSamplingInterval());
parametersList.add(parameters);
}
SubscriptionResult subscriptionResult = connector.createOPCUAAttributes(parametersList,
subscription.getRequestedPublishingInterval());
subscriptionResults.add(subscriptionResult);
}
createTangoAttributes(subscriptionResults);
logger.debug("init done for device {} ", deviceManager.getName());
}
/**
* delete device
*
* @throws DevFailed
*/
@Delete
public void delete() throws DevFailed {
logger.debug("delete");
}
@Override
protected DeviceManager getDeviceManager() {
return deviceManager;
}
@Override
protected Logger getLogger() {
return logger;
}
public void setDynamicManager(DynamicManager dynamicManager) {
this.dynamicManager = dynamicManager;
}
@Override
protected DynamicManager getDynamicManager() {
return dynamicManager;
}
public DeviceState getState() {
return state;
}
public void setState(final DeviceState state) {
this.state = state;
}
public String getStatus() {
return status;
}
public void setStatus(final String status) {
this.status = status;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment