2121
2222import org .apache .iotdb .commons .exception .pipe .PipeRuntimeCriticalException ;
2323import org .apache .iotdb .commons .exception .pipe .PipeRuntimeNonCriticalException ;
24- import org .apache .iotdb .commons .utils .PathUtils ;
2524import org .apache .iotdb .db .pipe .sink .util .sorter .PipeTableModelTabletEventSorter ;
2625import org .apache .iotdb .db .pipe .sink .util .sorter .PipeTreeModelTabletEventSorter ;
2726import org .apache .iotdb .db .utils .DateTimeUtils ;
7069
7170public class OpcUaNameSpace extends ManagedNamespaceWithLifecycle {
7271 public static final String NAMESPACE_URI = "urn:apache:iotdb:opc-server" ;
73- private final boolean isClientServerModel ;
7472 private final SubscriptionModel subscriptionModel ;
7573 private final OpcUaServerBuilder builder ;
76- private final String databaseName ;
7774 private final String placeHolder ;
7875
7976 OpcUaNameSpace (
80- final OpcUaServer server ,
81- final boolean isClientServerModel ,
82- final OpcUaServerBuilder builder ,
83- final String qualifiedDatabaseName ,
84- final String placeHolder ) {
77+ final OpcUaServer server , final OpcUaServerBuilder builder , final String placeHolder ) {
8578 super (server , NAMESPACE_URI );
86- this .isClientServerModel = isClientServerModel ;
8779 this .builder = builder ;
88- this .databaseName = PathUtils .unQualifyDatabaseName (qualifiedDatabaseName );
8980 this .placeHolder = placeHolder ;
9081
9182 subscriptionModel = new SubscriptionModel (server , this );
@@ -106,15 +97,17 @@ public void shutdown() {
10697 });
10798 }
10899
109- void transfer (final Tablet tablet , final boolean isTableModel ) throws UaException {
110- if (isClientServerModel ) {
111- transferTabletForClientServerModel (tablet , isTableModel );
100+ void transfer (final Tablet tablet , final boolean isTableModel , final OpcUaSink sink )
101+ throws UaException {
102+ if (sink .isClientServerModel ) {
103+ transferTabletForClientServerModel (tablet , isTableModel , sink );
112104 } else {
113- transferTabletForPubSubModel (tablet , isTableModel );
105+ transferTabletForPubSubModel (tablet , isTableModel , sink );
114106 }
115107 }
116108
117- private void transferTabletForClientServerModel (final Tablet tablet , final boolean isTableModel ) {
109+ private void transferTabletForClientServerModel (
110+ final Tablet tablet , final boolean isTableModel , final OpcUaSink sink ) {
118111 final List <IMeasurementSchema > schemas = tablet .getSchemas ();
119112 final List <IMeasurementSchema > newSchemas = new ArrayList <>();
120113 if (!isTableModel ) {
@@ -136,7 +129,7 @@ private void transferTabletForClientServerModel(final Tablet tablet, final boole
136129 }
137130
138131 transferTabletRowForClientServerModel (
139- tablet .getDeviceId ().split ("\\ ." ), newSchemas , timestamps , values );
132+ tablet .getDeviceId ().split ("\\ ." ), newSchemas , timestamps , values , sink );
140133 } else {
141134 new PipeTableModelTabletEventSorter (tablet ).sortByTimestampIfNecessary ();
142135
@@ -151,7 +144,7 @@ private void transferTabletForClientServerModel(final Tablet tablet, final boole
151144 for (int i = 0 ; i < tablet .getRowSize (); ++i ) {
152145 final Object [] segments = tablet .getDeviceID (i ).getSegments ();
153146 final String [] folderSegments = new String [segments .length + 1 ];
154- folderSegments [0 ] = databaseName ;
147+ folderSegments [0 ] = sink . unQualifiedDatabaseName ;
155148
156149 for (int j = 0 ; j < segments .length ; ++j ) {
157150 folderSegments [j + 1 ] = Objects .isNull (segments [j ]) ? placeHolder : (String ) segments [j ];
@@ -169,7 +162,8 @@ private void transferTabletForClientServerModel(final Tablet tablet, final boole
169162 ? null
170163 : getTabletObjectValue4Opc (
171164 tablet .getValues ()[index ], finalI , schemas .get (index ).getType ()))
172- .collect (Collectors .toList ()));
165+ .collect (Collectors .toList ()),
166+ sink );
173167 }
174168 }
175169 }
@@ -178,14 +172,18 @@ private void transferTabletRowForClientServerModel(
178172 final String [] segments ,
179173 final List <IMeasurementSchema > measurementSchemas ,
180174 final List <Long > timestamps ,
181- final List <Object > values ) {
175+ final List <Object > values ,
176+ final OpcUaSink sink ) {
182177 if (segments .length == 0 ) {
183178 throw new PipeRuntimeCriticalException ("The segments of tablets must exist" );
184179 }
185180 final StringBuilder currentStr = new StringBuilder ();
186181 UaNode folderNode = null ;
187182 NodeId folderNodeId ;
188- for (final String segment : segments ) {
183+ for (int i = 0 ;
184+ i < (Objects .isNull (sink .valueName ) ? segments .length : segments .length - 1 );
185+ ++i ) {
186+ final String segment = segments [i ];
189187 final UaNode nextFolderNode ;
190188
191189 currentStr .append (segment );
@@ -230,32 +228,50 @@ private void transferTabletRowForClientServerModel(
230228 }
231229
232230 final String currentFolder = currentStr .toString ();
231+ StatusCode currentQuality =
232+ Objects .isNull (sink .valueName ) ? StatusCode .GOOD : StatusCode .UNCERTAIN ;
233233 for (int i = 0 ; i < measurementSchemas .size (); ++i ) {
234234 if (Objects .isNull (values .get (i ))) {
235235 continue ;
236236 }
237237 final String name = measurementSchemas .get (i ).getMeasurementName ();
238238 final TSDataType type = measurementSchemas .get (i ).getType ();
239- final NodeId nodeId = newNodeId (currentFolder + name );
239+ if (Objects .nonNull (sink .qualityName ) && sink .qualityName .equals (name )) {
240+ if (!type .equals (TSDataType .BOOLEAN )) {
241+ throw new UnsupportedOperationException (
242+ "The quality value only supports boolean type, while true == GOOD and false == BAD." );
243+ }
244+ currentQuality = values .get (i ) == Boolean .TRUE ? StatusCode .GOOD : StatusCode .BAD ;
245+ continue ;
246+ }
247+ if (Objects .nonNull (sink .valueName ) && !sink .valueName .equals (name )) {
248+ throw new UnsupportedOperationException (
249+ "When the 'with-quality' mode is enabled, the measurement must be either \" value-name\" or \" quality-name\" " );
250+ }
251+ final String nodeName = Objects .isNull (sink .valueName ) ? name : segments [segments .length - 1 ];
252+ final NodeId nodeId = newNodeId (currentFolder + nodeName );
240253 final UaVariableNode measurementNode ;
241254 if (!getNodeManager ().containsNode (nodeId )) {
242255 measurementNode =
243256 new UaVariableNode .UaVariableNodeBuilder (getNodeContext ())
244- .setNodeId (newNodeId ( currentFolder + name ) )
257+ .setNodeId (nodeId )
245258 .setAccessLevel (AccessLevel .READ_WRITE )
246259 .setUserAccessLevel (AccessLevel .READ_ONLY )
247- .setBrowseName (newQualifiedName (name ))
248- .setDisplayName (LocalizedText .english (name ))
260+ .setBrowseName (newQualifiedName (nodeName ))
261+ .setDisplayName (LocalizedText .english (nodeName ))
249262 .setDataType (convertToOpcDataType (type ))
250263 .setTypeDefinition (Identifiers .BaseDataVariableType )
251264 .build ();
252265 getNodeManager ().addNode (measurementNode );
253- folderNode .addReference (
254- new Reference (
255- folderNode .getNodeId (),
256- Identifiers .Organizes ,
257- measurementNode .getNodeId ().expanded (),
258- true ));
266+ if (Objects .nonNull (folderNode )) {
267+ folderNode .addReference (
268+ new Reference (
269+ folderNode .getNodeId (), Identifiers .Organizes , nodeId .expanded (), true ));
270+ } else {
271+ measurementNode .addReference (
272+ new Reference (
273+ nodeId , Identifiers .Organizes , Identifiers .ObjectsFolder .expanded (), false ));
274+ }
259275 } else {
260276 // This must exist
261277 measurementNode =
@@ -275,7 +291,7 @@ private void transferTabletRowForClientServerModel(
275291 measurementNode .setValue (
276292 new DataValue (
277293 new Variant (values .get (i )),
278- StatusCode . GOOD ,
294+ currentQuality ,
279295 new DateTime (utcTimestamp ),
280296 new DateTime ()));
281297 }
@@ -319,8 +335,8 @@ private static long timestampToUtc(final long timeStamp) {
319335 * @param tablet the tablet to send
320336 * @throws UaException if failed to create {@link Event}
321337 */
322- private void transferTabletForPubSubModel (final Tablet tablet , final boolean isTableModel )
323- throws UaException {
338+ private void transferTabletForPubSubModel (
339+ final Tablet tablet , final boolean isTableModel , final OpcUaSink sink ) throws UaException {
324340 final BaseEventTypeNode eventNode =
325341 getServer ()
326342 .getEventFactory ()
@@ -331,7 +347,7 @@ private void transferTabletForPubSubModel(final Tablet tablet, final boolean isT
331347 if (isTableModel ) {
332348 sourceNameList = new ArrayList <>(tablet .getRowSize ());
333349 for (int i = 0 ; i < tablet .getRowSize (); ++i ) {
334- final StringBuilder idBuilder = new StringBuilder (databaseName );
350+ final StringBuilder idBuilder = new StringBuilder (sink . unQualifiedDatabaseName );
335351 for (final Object segment : tablet .getDeviceID (i ).getSegments ()) {
336352 idBuilder
337353 .append (TsFileConstant .PATH_SEPARATOR )
0 commit comments