Skip to content

Commit

Permalink
Merge pull request #212 from com-pas/feature/84_create_dataset
Browse files Browse the repository at this point in the history
feat(84): RSR-433 create datasets from extRef
  • Loading branch information
massifben authored Dec 29, 2022
2 parents aa6958d + 545062a commit fcc433a
Show file tree
Hide file tree
Showing 25 changed files with 1,050 additions and 307 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public TFCDA getFCDA(){
}

if(doName != null && doName.isDefined()){
tfcda.setDaName(doName.toString());
tfcda.setDoName(doName.toString());
}

if(daName != null && daName.isDefined()){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static SclReport updateAllExtRefIedNames(SCL scd) {
.filter(LN0Adapter::hasInputs)
.map(LN0Adapter::getInputsAdapter)
.map(inputsAdapter -> inputsAdapter.updateAllExtRefIedNames(icdSystemVersionToIed))
.flatMap(List::stream).collect(Collectors.toList());
.flatMap(List::stream).toList();

return new SclReport(sclRootAdapter, extRefErrors);
}
Expand All @@ -79,7 +79,7 @@ private static List<SclReportItem> checkIedCompasIcdHeaderAttributes(SclRootAdap
return null;
}
).filter(Objects::nonNull)
.collect(Collectors.toList());
.toList();
}

private static List<SclReportItem> checkIedUnityOfIcdSystemVersionUuid(SclRootAdapter sclRootAdapter) {
Expand All @@ -97,7 +97,7 @@ private static List<SclReportItem> checkIedUnityOfIcdSystemVersionUuid(SclRootAd
.collect(Collectors.joining(", ")),
"/IED/Private/compas:ICDHeader[@ICDSystemVersionUUID] must be unique" +
" but the same ICDSystemVersionUUID was found on several IED."))
.collect(Collectors.toList());
.toList();
}

public static SclReport createDataSetAndControlBlocks(SCL scd) {
Expand Down Expand Up @@ -127,7 +127,7 @@ private static SclReport createDataSetAndControlBlocks(SclRootAdapter sclRootAda
List<SclReportItem> sclReportItems = lDeviceAdapters
.map(LDeviceAdapter::createDataSetAndControlBlocks)
.flatMap(List::stream)
.collect(Collectors.toList());
.toList();
return new SclReport(sclRootAdapter, sclReportItems);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.lfenergy.compas.sct.commons.scl.dtt.DataTypeTemplateAdapter;
import org.lfenergy.compas.sct.commons.scl.dtt.EnumTypeAdapter;
import org.lfenergy.compas.sct.commons.scl.dtt.LNodeTypeAdapter;
import org.lfenergy.compas.sct.commons.util.ServiceSettingsType;

import java.util.*;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -46,7 +47,7 @@
* <li>{@link AbstractLNAdapter#getDAI <em>Returns the value of the <b>ResumedDataTemplate </b> containment reference By filter</em>}</li>
* <li>{@link AbstractLNAdapter#getDAIValues(ResumedDataTemplate) <em>Returns <b>DAI (sGroup, value) </b> containment reference list By <b>ResumedDataTemplate </b> filter</em>}</li>
*
* <li>{@link AbstractLNAdapter#getDataSetByRef(String) <em>Returns the value of the <b>TDataSet </b>object reference By the value of the <b>name </b>attribute </em>}</li>
* <li>{@link AbstractLNAdapter#getDataSetByName(String) <em>Returns the value of the <b>TDataSet </b>object reference By the value of the <b>name </b>attribute </em>}</li>
*
* <li>{@link AbstractLNAdapter#getControlBlocks(List, TServiceType) <em>Returns the value of the <b>ControlBlock </b>containment reference list that match <b>datSet </b> value of given <b>TDataSet</b> </em>}</li>
* <li>{@link AbstractLNAdapter#addPrivate <em>Add <b>TPrivate </b>under this object</em>}</li>
Expand Down Expand Up @@ -140,11 +141,12 @@ protected void addControlBlock(ControlBlock<?> controlBlock) throws ScdException
}
}

public Optional<TDataSet> findDataSetByRef(String dataSetRef) {
public Optional<DataSetAdapter> findDataSetByName(String dataSetName) {
return currentElem.getDataSet()
.stream()
.filter(tDataSet -> Objects.equals(tDataSet.getName(), dataSetRef))
.findFirst();
.filter(tDataSet -> Objects.equals(tDataSet.getName(), dataSetName))
.findFirst()
.map(dataSet -> new DataSetAdapter(this, dataSet));
}

public DOIAdapter getDOIAdapterByName(String doiName) throws ScdException {
Expand Down Expand Up @@ -345,9 +347,8 @@ public List<ControlBlock<?>> getControlBlocksForMatchingFCDA(@NonNull ExtRefInfo
*/
protected List<ControlBlock<?>> getControlBlocks(List<TDataSet> tDataSets, TServiceType serviceType) {
return tDataSets.stream()
.map(tDataSet -> getControlBlocksByDataSetRef(tDataSet.getName(), serviceType))
.flatMap(Collection::stream).toList();

.map(tDataSet -> getControlBlocksByDataSetRef(tDataSet.getName(), serviceType))
.flatMap(Collection::stream).toList();
}

/**
Expand Down Expand Up @@ -655,14 +656,22 @@ private boolean iedHasConfSG() {
return iedAdapter.isSettingConfig(this.parentAdapter.getInst());
}

/**
* Gets linked LDevice as parent
*
* @return <em>IEDAdapter</em> object
*/
private LDeviceAdapter getCurrentLDevice() {
return this.parentAdapter;
}

/**
* Gets linked IED as parent
*
* @return <em>IEDAdapter</em> object
*/
private IEDAdapter getCurrentIed() {
LDeviceAdapter lDeviceAdapter = this.parentAdapter;
return lDeviceAdapter.getParentAdapter();
return getCurrentLDevice().getParentAdapter();
}

/**
Expand Down Expand Up @@ -854,32 +863,17 @@ protected boolean matchesDataAttributes(String dataAttribute) {
/**
* Gets Data Set in LNode by its name
*
* @param dataSetRef Data Set name
* @param dataSetName Data Set name
* @return optional of <em>DataSetInfo</em>
*/
public Optional<DataSetInfo> getDataSetByRef(String dataSetRef) {
public Optional<DataSetInfo> getDataSetByName(String dataSetName) {
return currentElem.getDataSet()
.stream()
.filter(tDataSet -> tDataSet.getName().equals(dataSetRef))
.filter(tDataSet -> tDataSet.getName().equals(dataSetName))
.map(DataSetInfo::from)
.findFirst();
}

/**
* Adds Data Set to LNode Data Sets
*
* @param dataSetInfo data's of Data Set to add
*/
public void addDataSet(DataSetInfo dataSetInfo) {
TDataSet tDataSet = new TDataSet();
tDataSet.setName(dataSetInfo.getName());
tDataSet.getFCDA().addAll(
dataSetInfo.getFCDAInfos().stream().map(FCDAInfo::getFCDA).toList()
);
currentElem.getDataSet().add(tDataSet);

}

/**
* Gets DAI values for specified DA in summaraized Data Type Template
*
Expand Down Expand Up @@ -939,4 +933,25 @@ private void removeExtRefSourceBinding(final TExtRef tExtRef) {
tExtRef.unsetSrcLNClass();
}

/**
* Adds DataSet in specified LNode in current IED/AccessPoint.
* The AccessPoint must have DataSet creation capabilities
*
* @param dataSetName Name of the dataSet
* @param serviceSettingsType GOOSE, SMV or REPORT service type
* @throws ScdException throws when IED does not have DataSet creation capabilities
* @see LDeviceAdapter#hasDataSetCreationCapability
*/
public DataSetAdapter createDataSetIfNotExists(String dataSetName, ServiceSettingsType serviceSettingsType) {
return findDataSetByName(dataSetName).orElseGet(() -> {
if (!getCurrentLDevice().hasDataSetCreationCapability(serviceSettingsType)) {
throw new ScdException("IED/AccessPoint does not have capability to create DataSet of type %s in %s"
.formatted(serviceSettingsType, getXPath()));
}
TDataSet newDataSet = new TDataSet();
newDataSet.setName(dataSetName);
currentElem.getDataSet().add(newDataSet);
return new DataSetAdapter(this, newDataSet);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// SPDX-FileCopyrightText: 2022 RTE FRANCE
//
// SPDX-License-Identifier: Apache-2.0

package org.lfenergy.compas.sct.commons.scl.ied;


import org.apache.commons.lang3.StringUtils;
import org.lfenergy.compas.scl2007b4.model.TAnyLN;
import org.lfenergy.compas.scl2007b4.model.TDataSet;
import org.lfenergy.compas.scl2007b4.model.TFCDA;
import org.lfenergy.compas.scl2007b4.model.TFCEnum;
import org.lfenergy.compas.sct.commons.scl.SclElementAdapter;
import org.lfenergy.compas.sct.commons.util.Utils;

import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;

import static org.lfenergy.compas.sct.commons.util.Utils.*;

/**
* A representation of the model object
* <em><b>{@link DataSetAdapter DataSetAdapter}</b></em>.
* <p>
* The following features are supported:
* </p>
* <ol>
* <li>Principal functions</li>
* <ul>
* <li>{@link DataSetAdapter#findFCDA <em>look for a FCDA in this DataSet</em>}</li>
* <li>{@link DataSetAdapter#createFCDAIfNotExists <em>create a FCDA in this DataSet</em></li>
* </ul>
* </ol>
* <br/>
* <pre>
* <b>ObjectReference</b>: DataSet
* <b>LDName</b> = "name" key of the DataSet in the parent LN/LN0
* </pre>
*
* @see TLN0
* @see AbstractLNAdapter
*/
public class DataSetAdapter extends SclElementAdapter<AbstractLNAdapter<? extends TAnyLN>, TDataSet> {

/**
* IEC 61850 requires FCDA to be oredred inside a DataSet.
* This is the comparator to sort the FCDA inside a DataSet
*/
private static final Comparator<TFCDA> fcdaComparator = Comparator
.comparing(TFCDA::getLdInst, Utils::blanksFirstComparator)
.thenComparing(TFCDA::getPrefix, Utils::blanksFirstComparator)
.thenComparing(tfcda -> tfcda.isSetLnClass() ? tfcda.getLnClass().get(0) : null, Utils::blanksFirstComparator)
.thenComparing(tfcda -> tfcda.getLnInst() != null ? Integer.valueOf(tfcda.getLnInst()) : null, Comparator.nullsFirst(Integer::compareTo))
.thenComparing(TFCDA::getDoName, Utils::blanksFirstComparator)
.thenComparing(TFCDA::getDaName, Utils::blanksFirstComparator);

public DataSetAdapter(AbstractLNAdapter<? extends TAnyLN> parentAdapter, TDataSet dataSet) {
super(parentAdapter, dataSet);
}

/**
* Check if node is child of the reference node
*
* @return link parent child existence
*/
@Override
protected boolean amChildElementRef() {
return parentAdapter.getCurrentElem().isSetDataSet() && parentAdapter.getCurrentElem().getDataSet().stream().anyMatch(dataSet ->
Objects.equals(currentElem.getName(), dataSet.getName()));
}

/**
* Returns local XPath
* @return XPath for current element (not including parent XPath)
*/
@Override
protected String elementXPath() {
return String.format("DataSet[%s]", xpathAttributeFilter("name", currentElem.getName()));
}

/**
* Find a FCDA matching all given criteria.
* @param ldInst FCDA ldInst attribute
* @param prefix FCDA prefix attribute
* @param lnClass FCDA lnClass attribute
* @param lnInst FCDA lnInst attribute
* @param doName FCDA doName attribute
* @param daName FCDA daNae attribute
* @param fc FCDA fc attribute
* @return Matching FCDA in this DataSet when found, empty Optional otherwise.
*/
public Optional<TFCDA> findFCDA(String ldInst, String prefix, String lnClass, String lnInst, String doName, String daName, TFCEnum fc) {
if (!currentElem.isSetFCDA()) {
return Optional.empty();
}
return currentElem.getFCDA().stream()
.filter(tfcda ->
Objects.equals(ldInst, tfcda.getLdInst())
&& equalsOrBothBlank(prefix, tfcda.getPrefix())
&& tfcda.getLnClass().contains(lnClass)
&& equalsOrBothBlank(lnInst, tfcda.getLnInst())
&& Objects.equals(doName, tfcda.getDoName())
&& Objects.equals(fc, tfcda.getFc())
&& equalsOrBothBlank(daName, tfcda.getDaName()))
.findFirst();
}

/**
* Create a new FCDA in this DataSet.
* Does nothing if a FCDA with the given attribute already exists in this DataSet.
* @param ldInst FCDA ldInst attribute
* @param prefix FCDA prefix attribute
* @param lnClass FCDA lnClass attribute
* @param lnInst FCDA lnInst attribute
* @param doName FCDA doName attribute
* @param daName FCDA daNae attribute
* @param fc FCDA fc attribute
* @return created FCDA, or existing FCDA with the given attributes
*/
public TFCDA createFCDAIfNotExists(String ldInst, String prefix, String lnClass, String lnInst, String doName, String daName, TFCEnum fc) {
Objects.requireNonNull(fc); // fc is required by XSD
Optional<TFCDA> fcda = findFCDA(ldInst, prefix, lnClass, lnInst, doName, daName, fc);
return fcda
.orElseGet(() -> {
TFCDA newFcda = new TFCDA();
newFcda.setLdInst(nullIfBlank(ldInst));
newFcda.setPrefix(nullIfBlank(prefix));
if (StringUtils.isNotBlank(lnClass)) {
newFcda.getLnClass().add(lnClass);
}
newFcda.setLnInst(nullIfBlank(lnInst));
newFcda.setDoName(nullIfBlank(doName));
newFcda.setDaName(nullIfBlank(daName));
newFcda.setFc(fc);
currentElem.getFCDA().add(newFcda);
currentElem.getFCDA().sort(fcdaComparator);
return newFcda;
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import org.apache.commons.lang3.StringUtils;
import org.lfenergy.compas.scl2007b4.model.*;
import org.lfenergy.compas.sct.commons.dto.ControlBlock;
import org.lfenergy.compas.sct.commons.dto.DataSetInfo;
import org.lfenergy.compas.sct.commons.dto.ExtRefBindingInfo;
import org.lfenergy.compas.sct.commons.dto.ExtRefSignalInfo;
import org.lfenergy.compas.sct.commons.exception.ScdException;
Expand Down Expand Up @@ -44,7 +43,6 @@
* <li>{@link IEDAdapter#getServices Returns the value of the <b>Service </b>object</em>}</li>
* <li>{@link IEDAdapter#getPrivateHeader <em>Returns the value of the <b>TPrivate </b>containment reference list</em>}</li>
* <li>{@link IEDAdapter#getExtRefBinders <em>Returns the value of the <b>ExtRefBindingInfo </b>containment reference list By <b>ExtRefSignalInfo</b></em>}</li>
* <li>{@link IEDAdapter#createDataSet <em>Add <b>DataSetInfo </b> describing the children <b>TDataSet </b> that can be created under <b>TAnyLN</b></em>}</li>
* <li>{@link IEDAdapter#createControlBlock <em>Add <b>ControlBlock </b> describing the children <b>TControlBlock </b> that can be created under <b>TAnyLN</b></em>}</li>
* <li>{@link IEDAdapter#addPrivate <em>Add <b>TPrivate </b>under this object</em>}</li>
* <li>{@link IEDAdapter#updateLDeviceNodesType <em>Update <b>Type </b> describing the value of the children <b>TAnyLN</b></em>}</li>
Expand Down Expand Up @@ -304,33 +302,6 @@ public boolean isSettingConfig(String ldInst) {
return srv != null && srv.getSettingGroups() != null && srv.getSettingGroups().getConfSG() != null;
}

/**
* Adds Data Set in specified LNode in current IED
*
* @param dataSetInfo Data Set data to add (and LNode path)
* @param serviceSettingsType Type of DataSet to create
* @throws ScdException throws when IED is not able to add DataSet
*/
public void createDataSet(DataSetInfo dataSetInfo, ServiceSettingsType serviceSettingsType) throws ScdException {
LDeviceAdapter lDeviceAdapter = findLDeviceAdapterByLdInst(dataSetInfo.getHolderLDInst())
.orElseThrow(
() -> new ScdException(
String.format(
"Unknow LDevice(%s) in IED(%s)", dataSetInfo.getHolderLDInst(), currentElem.getName())
)
);
if (!lDeviceAdapter.hasDataSetCreationCapability(serviceSettingsType)) {
throw new ScdException("The AccessPoint does not have capability to create DataSet of type " + serviceSettingsType.toString());
}
AbstractLNAdapter<?> lNodeAdapter = AbstractLNAdapter.builder()
.withLDeviceAdapter(lDeviceAdapter)
.withLnClass(dataSetInfo.getHolderLnClass())
.withLnInst(dataSetInfo.getHolderLnInst())
.withLnPrefix(dataSetInfo.getHolderLnPrefix())
.build();
lNodeAdapter.addDataSet(dataSetInfo);
}

/**
* Creates Control Block in specified LNode in current IED
*
Expand Down Expand Up @@ -366,7 +337,7 @@ public ControlBlock<? extends ControlBlock> createControlBlock(ControlBlock<? ex
);
}

if (lnAdapter.getDataSetByRef(controlBlock.getDataSetRef()).isEmpty()) {
if (lnAdapter.getDataSetByName(controlBlock.getDataSetRef()).isEmpty()) {
throw new ScdException(
String.format(
"Control block %s references unknown dataSet in LNode %s%s%s",
Expand Down
Loading

0 comments on commit fcc433a

Please sign in to comment.