6
6
7
7
import lombok .Getter ;
8
8
import lombok .RequiredArgsConstructor ;
9
+ import lombok .extern .slf4j .Slf4j ;
9
10
import org .lfenergy .compas .scl2007b4 .model .*;
10
11
import org .lfenergy .compas .sct .commons .api .ExtRefEditor ;
11
12
import org .lfenergy .compas .sct .commons .api .LnEditor ;
21
22
import org .lfenergy .compas .sct .commons .scl .ied .IEDAdapter ;
22
23
import org .lfenergy .compas .sct .commons .scl .ldevice .LDeviceAdapter ;
23
24
import org .lfenergy .compas .sct .commons .scl .ln .AbstractLNAdapter ;
25
+ import org .lfenergy .compas .sct .commons .scl .ln .LnId ;
24
26
import org .lfenergy .compas .sct .commons .util .ActiveStatus ;
25
27
import org .lfenergy .compas .sct .commons .util .PrivateUtils ;
26
28
import org .lfenergy .compas .sct .commons .util .Utils ;
33
35
import static org .apache .commons .lang3 .StringUtils .*;
34
36
import static org .lfenergy .compas .sct .commons .util .CommonConstants .*;
35
37
38
+ @ Slf4j
36
39
@ RequiredArgsConstructor
37
40
public class ExtRefEditorService implements ExtRefEditor {
38
41
private static final String INVALID_OR_MISSING_ATTRIBUTES_IN_EXT_REF_BINDING_INFO = "Invalid or missing attributes in ExtRef binding info" ;
@@ -47,6 +50,7 @@ public class ExtRefEditorService implements ExtRefEditor {
47
50
private final IedService iedService ;
48
51
private final LdeviceService ldeviceService ;
49
52
private final LnEditor lnEditor ;
53
+ private final DataTypeTemplatesService dataTypeTemplatesService ;
50
54
51
55
@ Getter
52
56
private final List <SclReportItem > errorHandler = new ArrayList <>();
@@ -60,24 +64,27 @@ public class ExtRefEditorService implements ExtRefEditor {
60
64
* 4. Active LNode source object that should match the provided parameters<br/>
61
65
* 5. Valid DataTypeTemplate Object hierarchy that should match the DO/DA/BDA parameters<br/>
62
66
*
63
- * @param sclRootAdapter SCL scl object
67
+ * @param scl SCL object
64
68
* @param compasBay TCompasBay represent Bay Private
65
69
* @param channel TChannel represent parameters
66
70
* @return the IED sources matching the LDEPF parameters
67
71
*/
68
- private List <TIED > getIedSources (SclRootAdapter sclRootAdapter , TCompasBay compasBay , TChannel channel ) {
69
- return sclRootAdapter .streamIEDAdapters ()
70
- .filter (iedAdapter -> (channel .getBayScope ().equals (TCBScopeType .BAY_EXTERNAL )
71
- && iedAdapter .getPrivateCompasBay ().stream ().noneMatch (bay -> bay .getUUID ().equals (compasBay .getUUID ())))
72
- || (channel .getBayScope ().equals (TCBScopeType .BAY_INTERNAL )
73
- && iedAdapter .getPrivateCompasBay ().stream ().anyMatch (bay -> bay .getUUID ().equals (compasBay .getUUID ()))))
74
- .filter (iedAdapter -> doesIcdHeaderMatchLDEPFChannel (iedAdapter , channel ))
75
- .filter (iedAdapter -> getActiveSourceLDeviceByLDEPFChannel (iedAdapter , channel )
76
- .map (lDeviceAdapter -> getActiveLNSourceByLDEPFChannel (lDeviceAdapter , channel )
77
- .map (lnAdapter -> isValidDataTypeTemplate (lnAdapter , channel ))
72
+ private List <TIED > getIedSources (SCL scl , TCompasBay compasBay , TChannel channel ) {
73
+ return scl .getIED ()
74
+ .stream ()
75
+ .filter (tied -> {
76
+ Optional <TCompasBay > tCompasBay = PrivateUtils .extractCompasPrivate (tied , TCompasBay .class );
77
+ return (channel .getBayScope ().equals (TCBScopeType .BAY_EXTERNAL )
78
+ && tCompasBay .stream ().noneMatch (bay -> bay .getUUID ().equals (compasBay .getUUID ())))
79
+ || (channel .getBayScope ().equals (TCBScopeType .BAY_INTERNAL )
80
+ && tCompasBay .stream ().anyMatch (bay -> bay .getUUID ().equals (compasBay .getUUID ())));
81
+ }).filter (tied -> doesIcdHeaderMatchLDEPFChannel (tied , channel ))
82
+ .filter (tied -> ldeviceService .findLdevice (tied , channel .getLDInst ())
83
+ .filter (tlDevice -> ldeviceService .getLdeviceStatus (tlDevice ).map (ActiveStatus .ON ::equals ).orElse (false ))
84
+ .map (tlDevice -> getActiveLNSourceByLDEPFChannel (tlDevice , channel )
85
+ .map (tAnyLN -> isValidDataTypeTemplate (scl .getDataTypeTemplates (), tAnyLN , channel ))
78
86
.orElse (false ))
79
87
.orElse (false ))
80
- .map (IEDAdapter ::getCurrentElem )
81
88
.limit (2 )
82
89
.toList ();
83
90
}
@@ -126,83 +133,58 @@ private static Boolean doesExtRefMatchLDEPFChannel(TExtRef extRef, TChannel tCha
126
133
/**
127
134
* Verify whether the IED satisfies the EPF channel for the private element `TCompasICDHeader`
128
135
*
129
- * @param iedAdapter IEDAdapter
136
+ * @param tied TIED
130
137
* @param channel TChannel
131
138
* @return true if the TCompasICDHeader matches the EPF channel
132
139
*/
133
- private static boolean doesIcdHeaderMatchLDEPFChannel (IEDAdapter iedAdapter , TChannel channel ) {
134
- return iedAdapter . getCompasICDHeader ()
135
- .map (compasICDHeader -> compasICDHeader .getIEDType ().value ().equals (channel .getIEDType ())
140
+ private static boolean doesIcdHeaderMatchLDEPFChannel (TIED tied , TChannel channel ) {
141
+ Optional < TCompasICDHeader > tCompasICDHeader = PrivateUtils . extractCompasPrivate ( tied , TCompasICDHeader . class );
142
+ return tCompasICDHeader .map (compasICDHeader -> compasICDHeader .getIEDType ().value ().equals (channel .getIEDType ())
136
143
&& compasICDHeader .getIEDredundancy ().value ().equals (channel .getIEDRedundancy ().value ())
137
144
&& compasICDHeader .getIEDSystemVersioninstance ().toString ().equals (channel .getIEDSystemVersionInstance ()))
138
145
.orElse (false );
139
146
}
140
147
141
- /**
142
- * Provides Active LDevice according to EPF channel's inst attribute
143
- *
144
- * @param iedAdapter IEDAdapter
145
- * @param channel TChannel
146
- * @return LDeviceAdapter object that matches the EPF channel
147
- */
148
- private Optional <LDeviceAdapter > getActiveSourceLDeviceByLDEPFChannel (IEDAdapter iedAdapter , TChannel channel ) {
149
- return ldeviceService .findLdevice (iedAdapter .getCurrentElem (), channel .getLDInst ())
150
- .filter (tlDevice -> ldeviceService .getLdeviceStatus (tlDevice ).map (ActiveStatus .ON ::equals ).orElse (false ))
151
- .map (tlDevice -> new LDeviceAdapter (iedAdapter , tlDevice ));
152
- }
153
-
154
148
/**
155
149
* Provides Active LN Object that satisfies the EPF channel attributes (lnClass, lnInst, prefix)
156
150
*
157
- * @param lDeviceAdapter LDeviceAdapter
151
+ * @param tlDevice TLDevice
158
152
* @param channel TChannel
159
153
* @return AbstractLNAdapter object that matches the EPF channel
160
154
*/
161
- private static Optional <AbstractLNAdapter <?>> getActiveLNSourceByLDEPFChannel (LDeviceAdapter lDeviceAdapter , TChannel channel ) {
162
- return lDeviceAdapter .getLNAdaptersIncludingLN0 ()
163
- .stream ()
164
- .filter (lnAdapter -> lnAdapter .getLNClass ().equals (channel .getLNClass ())
165
- && lnAdapter .getLNInst ().equals (channel .getLNInst ())
166
- && trimToEmpty (channel .getLNPrefix ()).equals (trimToEmpty (lnAdapter .getPrefix ())))
155
+ private Optional <TAnyLN > getActiveLNSourceByLDEPFChannel (TLDevice tlDevice , TChannel channel ) {
156
+ return lnEditor .getAnylns (tlDevice )
157
+ .filter (tAnyLN -> lnEditor .matchesLn (tAnyLN , channel .getLNClass (), channel .getLNInst (), channel .getLNPrefix ()))
167
158
.findFirst ()
168
- .filter (lnAdapter -> lnAdapter .getDaiModStValValue ()
169
- .map (status -> status .equals (ActiveStatus .ON .getValue ()))
170
- .orElse (true ));
159
+ .filter (tAnyLN -> lnEditor .getDaiModStValValue (tAnyLN ).map (ActiveStatus .ON ::equals ).orElse (true ));
171
160
}
172
161
173
162
/**
174
163
* Verify whether the LN satisfies the EPF channel parameters for Data Type Template elements.
175
164
*
176
- * @param lnAdapter AbstractLNAdapter
165
+ * @param dtt TDataTypeTemplates
166
+ * @param tAnyLN TAnyLN
177
167
* @param channel TChannel
178
168
* @return true if the LN matches the EPF channel
179
169
*/
180
- private static boolean isValidDataTypeTemplate (AbstractLNAdapter <?> lnAdapter , TChannel channel ) {
170
+ private boolean isValidDataTypeTemplate (TDataTypeTemplates dtt , TAnyLN tAnyLN , TChannel channel ) {
181
171
if (isBlank (channel .getDOName ())) {
182
172
return true ;
183
173
}
184
174
String doName = isBlank (channel .getDOInst ()) || channel .getDOInst ().equals ("0" ) ? channel .getDOName () : channel .getDOName () + channel .getDOInst ();
185
- DoTypeName doTypeName = new DoTypeName (doName );
175
+ String daName = channel .getDAName ();
176
+ List <String > sdoNames = new ArrayList <>();
177
+ List <String > bdaNames = new ArrayList <>();
186
178
if (isNotBlank (channel .getSDOName ())) {
187
- doTypeName . getStructNames () .add (channel .getSDOName ());
179
+ sdoNames .add (channel .getSDOName ());
188
180
}
189
- DaTypeName daTypeName = new DaTypeName (channel .getDAName ());
190
181
if (isNotBlank (channel .getBDAName ())) {
191
- daTypeName .setBType (TPredefinedBasicTypeEnum .STRUCT );
192
- daTypeName .getStructNames ().add (channel .getBDAName ());
182
+ bdaNames .add (channel .getBDAName ());
193
183
}
194
184
if (isNotBlank (channel .getSBDAName ())) {
195
- daTypeName . getStructNames () .add (channel .getSBDAName ());
185
+ bdaNames .add (channel .getSBDAName ());
196
186
}
197
- return lnAdapter .getDataTypeTemplateAdapter ().getLNodeTypeAdapterById (lnAdapter .getLnType ())
198
- .filter (lNodeTypeAdapter -> {
199
- try {
200
- lNodeTypeAdapter .checkDoAndDaTypeName (doTypeName , daTypeName );
201
- } catch (ScdException ex ) {
202
- return false ;
203
- }
204
- return true ;
205
- }).isPresent ();
187
+ return dataTypeTemplatesService .findDoLinkedToDa (dtt , tAnyLN .getLnType (), new DoLinkedToDaFilter (doName , sdoNames , daName , bdaNames )).isPresent ();
206
188
}
207
189
208
190
@ Override
@@ -266,19 +248,18 @@ public TExtRef updateExtRefSource(SCL scd, ExtRefInfo extRefInfo) throws ScdExce
266
248
@ Override
267
249
public List <SclReportItem > manageBindingForLDEPF (SCL scd , EPF epf ) {
268
250
errorHandler .clear ();
269
- SclRootAdapter sclRootAdapter = new SclRootAdapter (scd );
270
251
if (!epf .isSetChannels ()) return errorHandler ;
252
+ log .info ("Processing %d EPF setting channels" .formatted (epf .getChannels ().getChannel ().size ()));
271
253
iedService .getFilteredIeds (scd , ied -> !ied .getName ().contains ("TEST" ))
272
254
.forEach (tied -> ldeviceService .findLdevice (tied , tlDevice -> tlDevice .getInst ().equals (LDEVICE_LDEPF ))
273
255
.filter (ldepfLdevice -> PrivateUtils .extractStringPrivate (ldepfLdevice .getLN0 (), COMPAS_LNODE_STATUS ).map (status -> !status .equals ("off" )).orElse (false ))
274
256
.ifPresent (ldepfLdevice -> getExtRefWithBayReferenceInLDEPF (tied , ldepfLdevice )
275
257
.forEach (extRefBayRef -> epf .getChannels ().getChannel ().stream ().filter (tChannel -> doesExtRefMatchLDEPFChannel (extRefBayRef .extRef (), tChannel ))
276
258
.findFirst ().ifPresent (channel -> {
277
- List <TIED > iedSources = getIedSources (sclRootAdapter , extRefBayRef .compasBay (), channel );
259
+ List <TIED > iedSources = getIedSources (scd , extRefBayRef .compasBay (), channel );
278
260
if (iedSources .size () == 1 ) {
279
261
updateLDEPFExtRefBinding (extRefBayRef , iedSources .getFirst (), channel );
280
- LDeviceAdapter lDeviceAdapter = new LDeviceAdapter (new IEDAdapter (sclRootAdapter , tied .getName ()), ldepfLdevice );
281
- updateLDEPFDos (lDeviceAdapter , extRefBayRef .extRef (), channel );
262
+ updateLDEPFDos (scd .getDataTypeTemplates (), tied , ldepfLdevice , extRefBayRef .extRef (), channel );
282
263
} else {
283
264
if (iedSources .size () > 1 ) {
284
265
errorHandler .add (SclReportItem .warning (null , "There is more than one IED source to bind the signal " +
@@ -344,42 +325,6 @@ private void updateLDEPFExtRefBinding(ExtRefInfo.ExtRefWithBayReference extRefWi
344
325
}
345
326
}
346
327
347
- private void updateLDEPFDos (LDeviceAdapter lDeviceAdapter , TExtRef extRef , TChannel setting ) {
348
- if (setting .getChannelType ().equals (TChannelType .DIGITAL )) {
349
- //digital
350
- lDeviceAdapter .findLnAdapter (LN_RBDR , setting .getChannelNum (), null )
351
- .ifPresent (lnAdapter -> DO_DA_MAPPINGS .forEach (doNameAndDaName -> updateVal (lnAdapter , doNameAndDaName , extRef , setting )));
352
- lDeviceAdapter .findLnAdapter (LN_RBDR , setting .getChannelNum (), LN_PREFIX_B )
353
- .ifPresent (lnAdapter -> DO_DA_MAPPINGS .forEach (doNameAndDaName -> updateVal (lnAdapter , doNameAndDaName , extRef , setting )));
354
- }
355
- if (setting .getChannelType ().equals (TChannelType .ANALOG )) {
356
- //analog
357
- lDeviceAdapter .findLnAdapter (LN_RADR , setting .getChannelNum (), null )
358
- .ifPresent (lnAdapter -> DO_DA_MAPPINGS .forEach (doNameAndDaName -> updateVal (lnAdapter , doNameAndDaName , extRef , setting )));
359
- lDeviceAdapter .findLnAdapter (LN_RADR , setting .getChannelNum (), LN_PREFIX_A )
360
- .ifPresent (lnAdapter -> DO_DA_MAPPINGS .forEach (doNameAndDaName -> updateVal (lnAdapter , doNameAndDaName , extRef , setting )));
361
- }
362
- }
363
-
364
- private void updateVal (AbstractLNAdapter <?> lnAdapter , DoNameAndDaName doDaName , TExtRef extRef , TChannel setting ) {
365
- String lnPrefix = lnAdapter .getPrefix ();
366
- Optional <SclReportItem > sclReportItem = switch (doDaName .daName ) {
367
- case DU_DA_NAME -> setting .isSetChannelShortLabel () ? lnAdapter .getDOIAdapterByName (doDaName .doName ).updateDAI (doDaName .daName , setting .getChannelShortLabel ()) :
368
- Optional .empty ();
369
- case SETVAL_DA_NAME -> {
370
- if (LN_PREFIX_B .equals (lnPrefix ) || LN_PREFIX_A .equals (lnPrefix )) {
371
- yield setting .isSetChannelLevModQ () && !setting .getChannelLevModQ ().equals (TChannelLevMod .NA ) ? lnAdapter .getDOIAdapterByName (doDaName .doName ).updateDAI (doDaName .daName , setting .getChannelLevModQ ().value ()) : Optional .empty ();
372
- } else {
373
- yield setting .isSetChannelLevMod () && !setting .getChannelLevMod ().equals (TChannelLevMod .NA ) ? lnAdapter .getDOIAdapterByName (doDaName .doName ).updateDAI (doDaName .daName , setting .getChannelLevMod ().value ()) : Optional .empty ();
374
- }
375
- }
376
- case STVAL_DA_NAME -> lnAdapter .getDOIAdapterByName (doDaName .doName ).updateDAI (doDaName .daName , ActiveStatus .ON .getValue ());
377
- case SETSRCREF_DA_NAME -> lnAdapter .getDOIAdapterByName (doDaName .doName ).updateDAI (doDaName .daName , computeDaiValue (lnPrefix , extRef , setting .getDAName ()));
378
- default -> throw new IllegalStateException ("Unexpected value: " + doDaName .daName );
379
- };
380
- sclReportItem .ifPresent (errorHandler ::add );
381
- }
382
-
383
328
private String computeDaiValue (String lnPrefix , TExtRef extRef , String daName ) {
384
329
if (LN_PREFIX_B .equals (lnPrefix ) || LN_PREFIX_A .equals (lnPrefix )) {
385
330
return extRef .getIedName () +
@@ -399,6 +344,63 @@ private String computeDaiValue(String lnPrefix, TExtRef extRef, String daName) {
399
344
}
400
345
}
401
346
347
+ private void updateLDEPFDos (TDataTypeTemplates dtt , TIED tied , TLDevice tlDevice , TExtRef tExtRef , TChannel setting ) {
348
+ // Digital
349
+ if (setting .getChannelType ().equals (TChannelType .DIGITAL )) {
350
+ lnEditor .findLn (tlDevice , tAnyLN -> lnEditor .matchesLn (tAnyLN , LN_RBDR , setting .getChannelNum (), null ))
351
+ .ifPresent (tln -> updateDaiValue (dtt , tied , tlDevice , tln , tExtRef , setting ));
352
+ lnEditor .findLn (tlDevice , tAnyLN -> lnEditor .matchesLn (tAnyLN , LN_RBDR , setting .getChannelNum (), LN_PREFIX_B ))
353
+ .ifPresent (tln -> updateDaiValue (dtt , tied , tlDevice , tln , tExtRef , setting ));
354
+ }
355
+ // Analog
356
+ if (setting .getChannelType ().equals (TChannelType .ANALOG )) {
357
+ lnEditor .findLn (tlDevice , tAnyLN -> lnEditor .matchesLn (tAnyLN , LN_RADR , setting .getChannelNum (), null ))
358
+ .ifPresent (tln -> updateDaiValue (dtt , tied , tlDevice , tln , tExtRef , setting ));
359
+ lnEditor .findLn (tlDevice , tAnyLN -> lnEditor .matchesLn (tAnyLN , LN_RADR , setting .getChannelNum (), LN_PREFIX_A ))
360
+ .ifPresent (tln -> updateDaiValue (dtt , tied , tlDevice , tln , tExtRef , setting ));
361
+ }
362
+ }
363
+
364
+ private void updateDaiValue (TDataTypeTemplates dtt , TIED tied , TLDevice tlDevice , TAnyLN tln , TExtRef tExtRef , TChannel setting ) {
365
+ DO_DA_MAPPINGS .forEach (doNameAndDaName -> Optional .ofNullable (getNewDaiValue (doNameAndDaName .daName , LnId .from (tln ).prefix (), tExtRef , setting ))
366
+ .ifPresent (newDaiValue -> updateDaiVal (dtt , tied , tlDevice , tln , DoLinkedToDaFilter .from (doNameAndDaName .doName , doNameAndDaName .daName ), newDaiValue )));
367
+ }
368
+
369
+ private String getNewDaiValue (String daName , String lnPrefix , TExtRef extRef , TChannel setting ) {
370
+ return switch (daName ) {
371
+ case DU_DA_NAME -> setting .isSetChannelShortLabel () ? setting .getChannelShortLabel (): null ;
372
+ case SETVAL_DA_NAME -> {
373
+ if (LN_PREFIX_B .equals (lnPrefix ) || LN_PREFIX_A .equals (lnPrefix )){
374
+ yield setting .isSetChannelLevModQ () && !setting .getChannelLevModQ ().equals (TChannelLevMod .NA ) ? setting .getChannelLevModQ ().value (): null ;
375
+ } else {
376
+ yield setting .isSetChannelLevMod () && !setting .getChannelLevMod ().equals (TChannelLevMod .NA ) ? setting .getChannelLevMod ().value (): null ;
377
+ }
378
+ }
379
+ case STVAL_DA_NAME -> ActiveStatus .ON .getValue ();
380
+ case SETSRCREF_DA_NAME -> computeDaiValue (lnPrefix , extRef , setting .getDAName ());
381
+ default -> throw new IllegalStateException ("Unexpected value: " + setting .getDAName ());
382
+ };
383
+ }
384
+
385
+ private void updateDaiVal (TDataTypeTemplates dtt , TIED tied , TLDevice tlDevice , TAnyLN tln , DoLinkedToDaFilter doLinkedToDaFilter , String newDaiValue ) {
386
+ dataTypeTemplatesService .getFilteredDoLinkedToDa (dtt , tln .getLnType (), doLinkedToDaFilter )
387
+ .map (doLinkedToDa1 -> lnEditor .getDoLinkedToDaCompletedFromDAI (tied , tlDevice .getInst (), tln , doLinkedToDa1 ))
388
+ .findFirst ()
389
+ .filter (doLinkedToDa1 -> {
390
+ if (!doLinkedToDa1 .isUpdatable ()){
391
+ errorHandler .add (SclReportItem .warning (tied .getName () + "/" + LDEVICE_LDSUIED + "/" + LnId .from (tln ).lnClass () + "/DOI@name=\" " + doLinkedToDaFilter .doName () + "\" /DAI@name=\" " + doLinkedToDaFilter .daName () + "\" /Val" , "The DAI cannot be updated" ));
392
+ }
393
+ return doLinkedToDa1 .isUpdatable ();
394
+ })
395
+ .ifPresent (doLinkedToDa1 -> {
396
+ TVal tVal = new TVal ();
397
+ tVal .setValue (newDaiValue );
398
+ doLinkedToDa1 .dataAttribute ().addDaVal (tVal );
399
+ lnEditor .updateOrCreateDOAndDAInstances (tln , doLinkedToDa1 );
400
+ log .info ("LDEPF - Update DOI => LN(lnClass=%s, inst=%s, prefix=%s) / DOI(name=%s)/DAI(name=%s) with value=%s" .formatted (LnId .from (tln ).lnClass (), LnId .from (tln ).lnInst (), LnId .from (tln ).prefix (), doLinkedToDaFilter .doName (), doLinkedToDaFilter .daName (), newDaiValue ));
401
+ });
402
+ }
403
+
402
404
private record DoNameAndDaName (String doName , String daName ) {
403
405
}
404
406
0 commit comments