diff options
Diffstat (limited to 'sdnr')
23 files changed, 367 insertions, 209 deletions
diff --git a/sdnr/wt/data-provider/dblib/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/sqldb/data/SqlDBDataProvider.java b/sdnr/wt/data-provider/dblib/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/sqldb/data/SqlDBDataProvider.java index e04e109cd..02930304b 100644 --- a/sdnr/wt/data-provider/dblib/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/sqldb/data/SqlDBDataProvider.java +++ b/sdnr/wt/data-provider/dblib/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/database/sqldb/data/SqlDBDataProvider.java @@ -28,6 +28,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.sqldb.SqlDBClient; import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.sqldb.SqlDBConfig; @@ -87,6 +88,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.pro import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.UpdateNetworkElementConnectionInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.UpdateNetworkElementConnectionOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Filter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.FilterKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.mediator.server.list.output.Data; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -474,27 +476,27 @@ public class SqlDBDataProvider extends HtDatabaseEventsService implements Databa @Override public ReadGuiCutThroughEntryOutputBuilder readGuiCutThroughEntry(EntityInput input) { ReadGuiCutThroughEntryOutputBuilder outputBuilder = new ReadGuiCutThroughEntryOutputBuilder(); - QueryResult<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.Data> result = - this.guicutthroughRW.getData(input); if (!guicutthroughOverride.isEmpty()) { - List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.Data> gcData = - result.getResult(); - List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.Data> updatedGcData = - new ArrayList<>(); - for (int i = 0; i < gcData.size(); i++) { - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.Data gcDataItem = - gcData.get(i); - Guicutthrough gcItem = - new GuicutthroughBuilder().setId(gcDataItem.getId()).setName(gcDataItem.getName()) - .setWeburi(guicutthroughOverride + "/" + gcDataItem.getId()).build(); - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.DataBuilder gcDataBuilder = - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.DataBuilder( - gcItem); - updatedGcData.add(gcDataBuilder.build()); + if (input.getFilter() != null) { + // Iterate through the Filter map, get the ID and populate the GuicutThrough object accordingly. + Map<FilterKey, Filter> inputFilter = input.getFilter(); + List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.Data> gcData = + new ArrayList<>(); + for (FilterKey fk : inputFilter.keySet()) { + String fkVal = inputFilter.get(fk).getFiltervalue(); + if (fkVal != null) { + addGcItem(gcData, fkVal); + } + for (String fkVals : inputFilter.get(fk).getFiltervalues()) { + addGcItem(gcData, fkVals); + } + } + outputBuilder.setData(gcData); } - outputBuilder.setData(updatedGcData); } else { + QueryResult<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.Data> result = + this.guicutthroughRW.getData(input); outputBuilder.setData(result.getResult()); } outputBuilder.setPagination( @@ -503,6 +505,17 @@ public class SqlDBDataProvider extends HtDatabaseEventsService implements Databa return outputBuilder; } + private void addGcItem( + List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.Data> gcData, + String value) { + Guicutthrough gcItem = new GuicutthroughBuilder().setId(value).setName(value) + .setWeburi(guicutthroughOverride + "/" + value).build(); + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.DataBuilder gcDataBuilder = + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.read.gui.cut.through.entry.output.DataBuilder( + gcItem); + gcData.add(gcDataBuilder.build()); + } + @Override public boolean waitForYellowDatabaseStatus(long timeout, TimeUnit unit) { return true; diff --git a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/dataprovider/ORanDOMToInternalDataModel.java b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/dataprovider/ORanDOMToInternalDataModel.java index 4b55f1681..958e3bf72 100644 --- a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/dataprovider/ORanDOMToInternalDataModel.java +++ b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/dataprovider/ORanDOMToInternalDataModel.java @@ -21,27 +21,20 @@ */ package org.onap.ccsdk.features.sdnr.wt.devicemanager.oran.dataprovider; -import java.time.Instant; import java.util.ArrayList; import java.util.Collection; -import java.util.Date; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; -import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp; import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl; import org.onap.ccsdk.features.sdnr.wt.devicemanager.oran.util.ORanDMDOMUtility; import org.onap.ccsdk.features.sdnr.wt.devicemanager.oran.util.ORanDeviceManagerQNames; import org.onap.ccsdk.features.sdnr.wt.devicemanager.oran.yangspecs.ORANFM; import org.onap.ccsdk.features.sdnr.wt.devicemanager.oran.yangspecs.OnapSystem; -import org.opendaylight.mdsal.dom.api.DOMEvent; import org.opendaylight.mdsal.dom.api.DOMNotification; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.FaultlogBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.FaultlogEntity; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.Guicutthrough; @@ -66,14 +59,13 @@ import org.slf4j.LoggerFactory; public class ORanDOMToInternalDataModel { private static final Logger LOG = LoggerFactory.getLogger(ORanDOMToInternalDataModel.class); - private static final NetconfTimeStamp NETCONFTIME_CONVERTER = NetconfTimeStampImpl.getConverter(); public static List<Inventory> getInventoryList(NodeId nodeId, NormalizedNode hwData) { List<Inventory> inventoryResultList = new ArrayList<Inventory>(); ContainerNode hwContainer = (ContainerNode) hwData; - MapNode componentMap = (MapNode) hwContainer - .getChildByArg(new NodeIdentifier(ORanDeviceManagerQNames.IETF_HW_COMPONENT_LIST)); + MapNode componentMap = + (MapNode) hwContainer.getChildByArg(new NodeIdentifier(ORanDeviceManagerQNames.IETF_HW_COMPONENT_LIST)); Collection<MapEntryNode> componentMapEntries = componentMap.body(); for (MapEntryNode componentMapEntryNode : getRootComponents(componentMapEntries)) { @@ -203,7 +195,8 @@ public class ORanDOMToInternalDataModel { * @param sys * @return */ - public static Optional<Guicutthrough> getGuicutthrough(@Nullable AugmentationNode onapSysAugData, @NonNull OnapSystem onapSys) { + public static Optional<Guicutthrough> getGuicutthrough(@Nullable AugmentationNode onapSysAugData, + @NonNull OnapSystem onapSys) { if (onapSysAugData != null) { String name = ORanDMDOMUtility.getLeafValue(onapSysAugData, onapSys.getName()); @@ -232,62 +225,38 @@ public class ORanDOMToInternalDataModel { * @param counter to be integrated into data * @return FaultlogEntity with data */ - public static FaultlogEntity getFaultLog(DOMNotification notification, @NonNull ORANFM oranfm, NodeId nodeId, Integer counter) { + public static FaultlogEntity getFaultLog(DOMNotification notification, @NonNull ORANFM oranfm, NodeId nodeId) { ContainerNode cn = notification.getBody(); FaultlogBuilder faultAlarm = new FaultlogBuilder(); faultAlarm.setNodeId(nodeId.getValue()); faultAlarm.setObjectId(ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultSourceQName())); faultAlarm.setProblem(ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultTextQName())); - faultAlarm.setSeverity(getSeverityType( - ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultSeverityQName()), + faultAlarm.setSeverity(getSeverityType(ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultSeverityQName()), ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultIsClearedQName()).equals("true"))); - faultAlarm.setCounter(counter); + faultAlarm.setCounter(Integer.parseInt(ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultIdQName()))); faultAlarm.setId(ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultIdQName())); faultAlarm.setSourceType(SourceType.Netconf); - faultAlarm.setTimestamp(getEventTime(notification)); + faultAlarm.setTimestamp(NetconfTimeStampImpl.getConverter() + .getTimeStamp(ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultEventTimeQName()))); + return faultAlarm.build(); } - public static FaultlogEntity getFaultLog(UnkeyedListEntryNode activeAlarmEntry, ORANFM oranfm, NodeId nodeId, Integer counter) { + public static FaultlogEntity getFaultLog(UnkeyedListEntryNode activeAlarmEntry, ORANFM oranfm, NodeId nodeId) { FaultlogBuilder faultAlarm = new FaultlogBuilder(); faultAlarm.setNodeId(nodeId.getValue()); - faultAlarm.setObjectId(getObjectId( - ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultSourceQName()))); - faultAlarm.setProblem( - ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultTextQName())); + faultAlarm.setObjectId(ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultSourceQName())); + faultAlarm.setProblem(ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultTextQName())); faultAlarm.setSeverity(getSeverityType( ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultSeverityQName()), - ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultIsClearedQName()) - .equals("true"))); - faultAlarm.setCounter(counter); + ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultIsClearedQName()).equals("true"))); + faultAlarm.setCounter( + Integer.parseInt(ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultIdQName()))); faultAlarm.setId(ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultIdQName())); faultAlarm.setSourceType(SourceType.Netconf); - faultAlarm.setTimestamp(NetconfTimeStampImpl.getConverter().getTimeStamp( - ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultEventTimeQName()))); + faultAlarm.setTimestamp(NetconfTimeStampImpl.getConverter() + .getTimeStamp(ORanDMDOMUtility.getLeafValue(activeAlarmEntry, oranfm.getFaultEventTimeQName()))); return faultAlarm.build(); - - } - - /** - * Convert Instant to NETCONF DateAndTime - * @param eventTimeInstant - * @return DateAndTime - */ - public static DateAndTime getDateAndTimeOfInstant(Instant eventTimeInstant) { - Date eventDate = Date.from(eventTimeInstant); - return new DateAndTime(NETCONFTIME_CONVERTER.getTimeStamp(eventDate)); - } - - private static DateAndTime getEventTime(DOMNotification notification) { - DateAndTime eventTime; - Instant notificationEventTime = null; - if (notification instanceof DOMEvent) { - notificationEventTime = ((DOMEvent) notification).getEventInstant(); - eventTime = NetconfTimeStampImpl.getConverter().getTimeStamp(notificationEventTime.toString()); - } else { - eventTime = NetconfTimeStampImpl.getConverter().getTimeStamp(); - } - return eventTime; } /** @@ -319,14 +288,4 @@ public class ORanDOMToInternalDataModel { + " faultSeverity=" + faultSeverity); } - private static String getObjectId(String leafValue) { - // fault-source = /ietf-hardware:hardware/component[name='slot0-logical0'] - Pattern p = Pattern.compile("\\/ietf-hardware:hardware\\/component\\[name=\\'(.*)\\']"); - Matcher m = p.matcher(leafValue); - if (m.find()) { - return m.group(1); - } - return leafValue; - } - } diff --git a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/ORanDOMNetworkElement.java b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/ORanDOMNetworkElement.java index 72cda1679..50f1411d0 100644 --- a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/ORanDOMNetworkElement.java +++ b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/ORanDOMNetworkElement.java @@ -197,6 +197,7 @@ public class ORanDOMNetworkElement implements NetworkElement, IConfigChangedList * this.oRanFaultListenerRegistrationResult.close(); } ; */ databaseService.clearGuiCutThroughEntriesOfNode(getMountpointId()); + faultService.removeAllCurrentProblemsOfNode(getNodeId()); } @Override @@ -215,7 +216,9 @@ public class ORanDOMNetworkElement implements NetworkElement, IConfigChangedList } @Override - public void warmstart() {} + public void warmstart() { + faultService.removeAllCurrentProblemsOfNode(getNodeId()); + } @Override public Optional<NetconfAccessor> getAcessor() { @@ -307,12 +310,10 @@ public class ORanDOMNetworkElement implements NetworkElement, IConfigChangedList ContainerNode cn = (ContainerNode) oData.get(); UnkeyedListNode activeAlarmsList = (UnkeyedListNode) cn.childByArg(new NodeIdentifier(oranfm.get().getFaultActiveAlarmsQName())); - int counter = 0; for (UnkeyedListEntryNode activeAlarmEntry : activeAlarmsList.body()) faultService.faultNotification(ORanDOMToInternalDataModel.getFaultLog(activeAlarmEntry, oranfm.get(), - netconfDomAccessor.getNodeId(), Integer.valueOf(counter++))); + netconfDomAccessor.getNodeId())); } - } @Override diff --git a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/notification/ORanDOMFaultNotificationListener.java b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/notification/ORanDOMFaultNotificationListener.java index 3e99bcd6d..a6329d58e 100644 --- a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/notification/ORanDOMFaultNotificationListener.java +++ b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/notification/ORanDOMFaultNotificationListener.java @@ -63,7 +63,7 @@ public class ORanDOMFaultNotificationListener implements DOMNotificationListener private final @NonNull DataProvider databaseService; private final @NonNull ORANFM oranfm; - private Integer counter; //Local counter is assigned to Notifications + private Integer counter; //Local counter is assigned to Events in EventLog public ORanDOMFaultNotificationListener(@NonNull NetconfDomAccessor netconfDomAccessor, Optional<ORANFM> oranfm, @NonNull VESCollectorService vesCollectorService, @NonNull FaultService faultService, @@ -74,8 +74,8 @@ public class ORanDOMFaultNotificationListener implements DOMNotificationListener this.websocketManagerService = Objects.requireNonNull(websocketManagerService); this.databaseService = Objects.requireNonNull(databaseService); this.oranfm = oranfm.get(); - this.mapper = - new ORanDOMFaultToVESFaultMapper(netconfDomAccessor.getNodeId(), vesCollectorService, "AlarmNotif"); + this.mapper = new ORanDOMFaultToVESFaultMapper(netconfDomAccessor.getNodeId(), this.vesCollectorService, + this.oranfm, "AlarmNotif"); this.counter = 0; } @@ -112,18 +112,20 @@ public class ORanDOMFaultNotificationListener implements DOMNotificationListener // Send devicemanager specific notification for database and ODLUX Instant eventTimeInstant = ORanDMDOMUtility.getNotificationInstant(notification); faultService.faultNotification( - ORanDOMToInternalDataModel.getFaultLog(notification, oranfm, netconfDomAccessor.getNodeId(), counter)); + ORanDOMToInternalDataModel.getFaultLog(notification, oranfm, netconfDomAccessor.getNodeId())); // Send model specific notification to WebSocketManager - websocketManagerService.sendNotification(notification, netconfDomAccessor.getNodeId(), oranfm.getAlarmNotifQName()); + websocketManagerService.sendNotification(notification, netconfDomAccessor.getNodeId(), + oranfm.getAlarmNotifQName()); try { if (vesCollectorService.getConfig().isVESCollectorEnabled()) { - VESCommonEventHeaderPOJO header = mapper.mapCommonEventHeader(notification, eventTimeInstant, counter); - VESFaultFieldsPOJO body = mapper.mapFaultFields(notification, oranfm); + VESCommonEventHeaderPOJO header = mapper.mapCommonEventHeader(notification, eventTimeInstant); + VESFaultFieldsPOJO body = mapper.mapFaultFields(notification); VESMessage vesMsg = vesCollectorService.generateVESEvent(header, body); vesCollectorService.publishVESMessage(vesMsg); LOG.debug("VES Message is {}", vesMsg.getMessage()); - writeToEventLog(vesMsg.getMessage(), eventTimeInstant, oranfm.getAlarmNotifQName().getLocalName(), counter); + writeToEventLog(vesMsg.getMessage(), eventTimeInstant, oranfm.getAlarmNotifQName().getLocalName(), + counter); } } catch (JsonProcessingException | DateTimeParseException e) { LOG.debug("Can not convert event into VES message {}", notification, e); @@ -149,7 +151,7 @@ public class ORanDOMFaultNotificationListener implements DOMNotificationListener } eventlogBuilder.setNewValue(data); eventlogBuilder.setSourceType(SourceType.Netconf); - eventlogBuilder.setTimestamp(ORanDOMToInternalDataModel.getDateAndTimeOfInstant(eventTimeInstant)); + eventlogBuilder.setTimestamp(ORanDMDOMUtility.getDateAndTimeOfInstant(eventTimeInstant)); databaseService.writeEventLog(eventlogBuilder.build()); } diff --git a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/util/ORanDMDOMUtility.java b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/util/ORanDMDOMUtility.java index 708ba8a47..a13ffaa9d 100644 --- a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/util/ORanDMDOMUtility.java +++ b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/util/ORanDMDOMUtility.java @@ -24,11 +24,15 @@ package org.onap.ccsdk.features.sdnr.wt.devicemanager.oran.util; import com.google.common.base.VerifyException; import java.time.Instant; import java.util.Collection; +import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp; +import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl; import org.opendaylight.mdsal.dom.api.DOMEvent; import org.opendaylight.mdsal.dom.api.DOMNotification; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; @@ -42,6 +46,7 @@ import org.slf4j.LoggerFactory; public class ORanDMDOMUtility { public static final Logger LOG = LoggerFactory.getLogger(ORanDMDOMUtility.class); + private static final NetconfTimeStamp NETCONFTIME_CONVERTER = NetconfTimeStampImpl.getConverter(); public static String getKeyValue(MapEntryNode componentEntry) { NodeIdentifierWithPredicates componentKey = componentEntry.getIdentifier(); // list key @@ -86,4 +91,14 @@ public class ORanDMDOMUtility { } } + /** + * Convert Instant to NETCONF DateAndTime + * @param eventTimeInstant + * @return DateAndTime + */ + public static DateAndTime getDateAndTimeOfInstant(Instant eventTimeInstant) { + Date eventDate = Date.from(eventTimeInstant); + return new DateAndTime(NETCONFTIME_CONVERTER.getTimeStamp(eventDate)); + } + } diff --git a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/vesmapper/ORanDOMFaultToVESFaultMapper.java b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/vesmapper/ORanDOMFaultToVESFaultMapper.java index fabe26463..7c01ba252 100644 --- a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/vesmapper/ORanDOMFaultToVESFaultMapper.java +++ b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/vesmapper/ORanDOMFaultToVESFaultMapper.java @@ -85,15 +85,18 @@ public class ORanDOMFaultToVESFaultMapper { private final VESCollectorService vesProvider; private final String notifName; // Name + private final ORANFM oranfm; private final String nodeIdString; // Sourcename //Initialized during registration private String mfgName; private String uuid; private String modelName; - public ORanDOMFaultToVESFaultMapper(NodeId nodeId, VESCollectorService vesCollectorService, String notifName) { + public ORanDOMFaultToVESFaultMapper(NodeId nodeId, VESCollectorService vesCollectorService, ORANFM oranfm, + String notifName) { this.nodeIdString = nodeId.getValue(); this.vesProvider = vesCollectorService; + this.oranfm = oranfm; this.notifName = notifName; } @@ -109,29 +112,30 @@ public class ORanDOMFaultToVESFaultMapper { this.modelName = modelName; } - public VESCommonEventHeaderPOJO mapCommonEventHeader(DOMNotification notification, Instant eventTime, - int sequenceNo) { + public VESCommonEventHeaderPOJO mapCommonEventHeader(DOMNotification notification, Instant eventTime) { VESCommonEventHeaderPOJO vesCEH = new VESCommonEventHeaderPOJO(); + ContainerNode cn = notification.getBody(); vesCEH.setDomain(VES_EVENT_DOMAIN); vesCEH.setEventName(notifName); vesCEH.setEventType(VES_EVENTTYPE); vesCEH.setPriority(VES_EVENT_PRIORITY); - String eventId = notifName + "-" + Long.toUnsignedString(sequenceNo); + String eventId = + notifName + "-" + Integer.parseInt(ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultIdQName())); vesCEH.setEventId(eventId); vesCEH.setStartEpochMicrosec(eventTime.toEpochMilli() * 1000); vesCEH.setLastEpochMicrosec(eventTime.toEpochMilli() * 1000); vesCEH.setNfVendorName(mfgName); vesCEH.setReportingEntityName(vesProvider.getConfig().getReportingEntityName()); - vesCEH.setSequence(sequenceNo); + vesCEH.setSequence(Integer.parseInt(ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultIdQName()))); vesCEH.setSourceId(uuid); vesCEH.setSourceName(nodeIdString); return vesCEH; } - public VESFaultFieldsPOJO mapFaultFields(DOMNotification alarmNotif, ORANFM oranfm) { + public VESFaultFieldsPOJO mapFaultFields(DOMNotification alarmNotif) { VESFaultFieldsPOJO vesFaultFields = new VESFaultFieldsPOJO(); ContainerNode cn = alarmNotif.getBody(); vesFaultFields.setAlarmCondition(ORanDMDOMUtility.getLeafValue(cn, oranfm.getFaultIdQName())); diff --git a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/vesmapper/ORanDOMSupervisionNotifToVESMapper.java b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/vesmapper/ORanDOMSupervisionNotifToVESMapper.java index b87b93d80..f58351a6b 100644 --- a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/vesmapper/ORanDOMSupervisionNotifToVESMapper.java +++ b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/vesmapper/ORanDOMSupervisionNotifToVESMapper.java @@ -23,7 +23,7 @@ package org.onap.ccsdk.features.sdnr.wt.devicemanager.oran.vesmapper; import com.fasterxml.jackson.annotation.JsonProperty; import java.time.Instant; -import org.onap.ccsdk.features.sdnr.wt.devicemanager.oran.dataprovider.ORanDOMToInternalDataModel; +import org.onap.ccsdk.features.sdnr.wt.devicemanager.oran.util.ORanDMDOMUtility; import org.onap.ccsdk.features.sdnr.wt.devicemanager.service.VESCollectorService; import org.onap.ccsdk.features.sdnr.wt.devicemanager.types.VESCommonEventHeaderPOJO; import org.onap.ccsdk.features.sdnr.wt.devicemanager.types.VESStndDefinedFieldsPOJO; @@ -138,7 +138,7 @@ public class ORanDOMSupervisionNotifToVESMapper { IetfNotification ietfNotif = new IetfNotification(); ietfNotif.setOranSupervisionNotif(oruSuperNotif); - ietfNotif.setEventTime(ORanDOMToInternalDataModel.getDateAndTimeOfInstant(eventTimeInstant).getValue()); + ietfNotif.setEventTime(ORanDMDOMUtility.getDateAndTimeOfInstant(eventTimeInstant).getValue()); DataObject data = new DataObject(); data.setIetfNotification(ietfNotif); diff --git a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/yangspecs/ORANFM.java b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/yangspecs/ORANFM.java index 5be18e75b..a4ef8b9fa 100644 --- a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/yangspecs/ORANFM.java +++ b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/yangspecs/ORANFM.java @@ -39,23 +39,9 @@ public class ORANFM extends YangModule { public static final QNameModule ORANFM_2022_08_15 = QNameModule.create(XMLNamespace.of(NAMESPACE), Revision.of("2022-08-15")); private static final List<QNameModule> MODULES = Arrays.asList(ORANFM_2019_02_04, ORANFM_2022_08_15); -// private final QName ORAN_FM_ALARM_NOTIF; -// private final QName ORAN_FM_FAULT_ID; -// private final QName ORAN_FM_FAULT_SOURCE; -// private final QName ORAN_FM_FAULT_SEVERITY; -// private final QName ORAN_FM_FAULT_TEXT; -// private final QName ORAN_FM_FAULT_IS_CLEARED; - - ORANFM(NetconfDomAccessor netconfDomAccessor, QNameModule module) { super(netconfDomAccessor, module); -// ORAN_FM_ALARM_NOTIF = QName.create(module, "alarm-notif"); -// ORAN_FM_FAULT_ID = QName.create(module, "fault-id"); -// ORAN_FM_FAULT_SOURCE = QName.create(module, "fault-source"); -// ORAN_FM_FAULT_SEVERITY = QName.create(module, "fault-severity"); -// ORAN_FM_FAULT_TEXT = QName.create(module, "fault-text"); -// ORAN_FM_FAULT_IS_CLEARED = QName.create(module, "is-cleared"); } public QName getFaultSourceQName() { @@ -83,17 +69,17 @@ public class ORANFM extends YangModule { } public QName getFaultEventTimeQName() { - return getQName("event-time"); + return getQName("event-time"); } - + public QName getFaultActiveAlarmListQName() { - return getQName("active-alarm-list"); + return getQName("active-alarm-list"); } - + public QName getFaultActiveAlarmsQName() { - return getQName("active-alarms"); + return getQName("active-alarms"); } - + /** * Get specific instance, depending on capabilities * diff --git a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/TestORanDOMFaultNotificationListener.java b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/TestORanDOMFaultNotificationListener.java index de19bf1a2..65ad9fe55 100644 --- a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/TestORanDOMFaultNotificationListener.java +++ b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/TestORanDOMFaultNotificationListener.java @@ -133,7 +133,10 @@ public class TestORanDOMFaultNotificationListener { .withChild(ImmutableNodes.leafNode(oranfm.get().getFaultSourceQName(), "Slot-2-Port-B")) .withChild(ImmutableNodes.leafNode(oranfm.get().getFaultSeverityQName(), "MAJOR")) .withChild(ImmutableNodes.leafNode(oranfm.get().getFaultIsClearedQName(), "true")) - .withChild(ImmutableNodes.leafNode(oranfm.get().getFaultTextQName(), "CPRI Port Down")).build(); + .withChild(ImmutableNodes.leafNode(oranfm.get().getFaultTextQName(), "CPRI Port Down")) + .withChild( + ImmutableNodes.leafNode(oranfm.get().getFaultEventTimeQName(), "2024-02-29T09:33:31.000+00:00")) + .build(); } public static class NetconfDeviceNotification implements DOMNotification, DOMEvent { diff --git a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/TestORanDOMToInternalDataModel.java b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/TestORanDOMToInternalDataModel.java index 01502e49c..b86177cdb 100644 --- a/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/TestORanDOMToInternalDataModel.java +++ b/sdnr/wt/devicemanager-o-ran-sc/o-ran/ru-fh/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/devicemanager/oran/impl/dom/TestORanDOMToInternalDataModel.java @@ -183,7 +183,7 @@ public class TestORanDOMToInternalDataModel { public void testORANFault() { ContainerNode cn = createORANDOMFault(); NetconfDeviceNotification faultNotif = new NetconfDeviceNotification(cn, Instant.now()); - FaultlogEntity fle = ORanDOMToInternalDataModel.getFaultLog(faultNotif, oranfm.get(), nodeId, 1); + FaultlogEntity fle = ORanDOMToInternalDataModel.getFaultLog(faultNotif, oranfm.get(), nodeId); assertEquals(fle.getId(), "47"); } @@ -207,7 +207,7 @@ public class TestORanDOMToInternalDataModel { UnkeyedListNode activeAlarmsList = (UnkeyedListNode) cn.childByArg(new NodeIdentifier(oranfm.get().getFaultActiveAlarmsQName())); for (UnkeyedListEntryNode activeAlarmEntry : activeAlarmsList.body()) - ORanDOMToInternalDataModel.getFaultLog(activeAlarmEntry, oranfm.get(), new NodeId("nSky"), Integer.valueOf(0)); + ORanDOMToInternalDataModel.getFaultLog(activeAlarmEntry, oranfm.get(), new NodeId("nSky")); } public static ContainerNode createORANDOMFault() { @@ -216,7 +216,10 @@ public class TestORanDOMToInternalDataModel { .withChild(ImmutableNodes.leafNode(oranfm.get().getFaultSourceQName(), "Slot-2-Port-B")) .withChild(ImmutableNodes.leafNode(oranfm.get().getFaultSeverityQName(), "MAJOR")) .withChild(ImmutableNodes.leafNode(oranfm.get().getFaultIsClearedQName(), "true")) - .withChild(ImmutableNodes.leafNode(oranfm.get().getFaultTextQName(), "CPRI Port Down")).build(); + .withChild(ImmutableNodes.leafNode(oranfm.get().getFaultTextQName(), "CPRI Port Down")) + .withChild( + ImmutableNodes.leafNode(oranfm.get().getFaultEventTimeQName(), "2024-02-29T09:33:31.000+00:00")) + .build(); } public static class NetconfDeviceNotification implements DOMNotification, DOMEvent { diff --git a/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts b/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts index 187e9bccb..615faaed7 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts @@ -24,6 +24,7 @@ import { flattenViewElements, getReferencedDataList, resolveViewDescription, + createViewData, } from '../utilities/viewEngineHelper'; export class EnableValueSelector extends Action { @@ -62,6 +63,12 @@ export class UpdateOutputData extends Action { } } +export class UpdateNewData extends Action { + constructor(public newData: any) { + super(); + } +} + export const updateNodeIdAsyncActionCreator = (nodeId: string) => async (dispatch: Dispatch, _getState: () => IApplicationStoreState ) => { dispatch(new UpdateDeviceDescription('', {}, [])); @@ -138,6 +145,8 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: let currentNS: string | null = null; let defaultNS: string | null = null; + let newData: any = null; + dispatch(new SetCollectingSelectionData(true)); try { for (let ind = 0; ind < pathParts.length; ++ind) { @@ -150,32 +159,27 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: viewElement = viewSpecification.elements[property] || viewSpecification.elements[`${namespace}:${property}`]; if (!viewElement) throw Error('Property [' + property + '] does not exist.'); - if (viewElement.isList && !key) { - if (pathParts.length - 1 > ind) { - dispatch(new SetCollectingSelectionData(false)); - throw new Error('No key for list [' + property + ']'); - } else if (vPath.endsWith('[]') && pathParts.length - 1 === ind) { + if (newData) { + // update view data + newData = newData[property]; - // empty key is used for new element - if (viewElement && 'viewId' in viewElement) viewSpecification = views[+viewElement.viewId]; - const data = Object.keys(viewSpecification.elements).reduce<{ [name: string]: any }>((acc, cur) => { - const elm = viewSpecification.elements[cur]; - if (elm.default) { - acc[elm.id] = elm.default || ''; - } - return acc; - }, {}); + } else if (viewElement.isList && !key) { + // handle new list element without key + if (pathParts[ind][1] === null) { - // create display specification - const ds: DisplaySpecification = { - displayMode: DisplayModeType.displayAsObject, - viewSpecification: resolveViewDescription(defaultNS, vPath, viewSpecification), - keyProperty: isViewElementList(viewElement!) && viewElement.key || undefined, - }; + // create new data if not already exists + newData = getState().configuration.viewDescription.newData; + if (!newData && viewElement && 'viewId' in viewElement) { + newData = createViewData(namespace, views[+viewElement.viewId], views); + dispatch(new UpdateNewData(newData)); + } - // update display specification - return dispatch(postProcessDisplaySpecificationActionCreator(vPath, data, ds)); + } else if ((pathParts.length) - 1 > ind) { + // handle list without key which is not a new element + dispatch(new SetCollectingSelectionData(false)); + throw new Error('No key for list [' + property + ']'); } + if (viewElement && isViewElementList(viewElement) && viewSpecification.parentView === '0') { // check if there is a reference as key const listSpecification = views[+viewElement.viewId]; @@ -232,8 +236,7 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: } extractList = true; } else { - // normal case & replaces unicode %2C if present - dataPath += `/${property}${key ? `=${key.replace(/,/ig, '%2C').replace(/\//ig, '%2F')}` : ''}`; + dataPath += `/${property}${key ? `=${key.replace(/\//ig, '%2F')}` : ''}`; // in case of the root element the required namespace will be added later, // while extracting the data @@ -248,7 +251,7 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: } else if (viewElement.uiType === 'rpc') { viewSpecification = views[+(viewElement.inputViewId || 0)]; - // create new instance & flaten + // create new instance & flatten inputViewSpecification = viewElement.inputViewId != null && { ...views[+(viewElement.inputViewId || 0)], elements: flattenViewElements(defaultNS, '', views[+(viewElement.inputViewId || 0)].elements, views, viewElement.label), @@ -261,11 +264,44 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: } } + if (newData) { + // create display specification + const ds: DisplaySpecification = { + displayMode: DisplayModeType.displayAsObject, + viewSpecification: resolveViewDescription(defaultNS, vPath, viewSpecification), + keyProperty: isViewElementList(viewElement!) && viewElement.key || undefined, + }; + + // update display specification + return dispatch(postProcessDisplaySpecificationActionCreator(vPath, newData, ds)); + } + let data: any = {}; // do not get any data from netconf if there is no view specified || this is the root element [0] || this is an rpc if (viewSpecification && !(viewSpecification.id === '0' || viewElement!.uiType === 'rpc')) { const restResult = (await restService.getConfigData(dataPath)); - if (!restResult.data) { + if (restResult.status === 409) { + // special case: if this is a list without any response + if (isViewElementList(viewElement!)) { + // create display specification + const ds: DisplaySpecification = { + displayMode: extractList ? DisplayModeType.displayAsList : DisplayModeType.displayAsObject, + viewSpecification: resolveViewDescription(defaultNS, vPath, viewSpecification), + keyProperty: viewElement.key, + }; + // update display specification + return dispatch(postProcessDisplaySpecificationActionCreator(vPath, [], ds)); + } else { + // create display specification + const ds: DisplaySpecification = { + displayMode: DisplayModeType.displayAsObject, + viewSpecification: resolveViewDescription(defaultNS, vPath, viewSpecification), + }; + // update display specification + return dispatch(postProcessDisplaySpecificationActionCreator(vPath, { }, ds)); + } + + } else if (!restResult.data) { // special case: if this is a list without any response if (extractList && restResult.status === 404) { if (!isViewElementList(viewElement!)) { @@ -360,6 +396,9 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async let currentNS: string | null = null; let defaultNS: string | null = null; + let newData: any = null; + let newElement: any = null; + dispatch(new SetCollectingSelectionData(true)); try { for (let ind = 0; ind < pathParts.length; ++ind) { @@ -371,24 +410,40 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async viewElement = viewSpecification.elements[property] || viewSpecification.elements[`${namespace}:${property}`]; if (!viewElement) throw Error('Property [' + property + '] does not exist.'); - if (isViewElementList(viewElement) && !key) { + if (newElement) { + // update view data + if (pathParts.length - 1 === ind) { + newElement[property] = data; + return dispatch(new UpdateNewData(newData)); + } else { + newElement[property] = Array.isArray(newElement[property]) ? [ ...newElement[property] ] : { ...newElement[property] }; + } + } else if (isViewElementList(viewElement) && !key) { embedList = true; if (viewElement && viewElement.isList && viewSpecification.parentView === '0') { - throw new Error('Found a list at root level of a module w/o a refenrece key.'); + throw new Error('Found a list at root level of a module w/o a reference key.'); } - if (pathParts.length - 1 > ind) { + + if (key === null) { + // set new data + const stateData = getState().configuration.viewDescription.newData; + newElement = newData = Array.isArray(stateData) ? [ ...stateData ] : { ...stateData }; + + if (vPath.endsWith('[]') && pathParts.length - 1 === ind) { + // handle new element with any number of arguments + let keyList = viewElement.key?.split(' '); + let dataPathParam = keyList?.map(id => data[id]).join(','); + key = viewElement.key && String(dataPathParam) || ''; + isNew = key; + if (!key) { + dispatch(new SetCollectingSelectionData(false)); + throw new Error('No value for key [' + viewElement.key + '] in list [' + property + ']'); + } + } + + } else if (pathParts.length - 1 > ind) { dispatch(new SetCollectingSelectionData(false)); throw new Error('No key for list [' + property + ']'); - } else if (vPath.endsWith('[]') && pathParts.length - 1 === ind) { - // handle new element with any number of arguments - let keyList = viewElement.key?.split(' '); - let dataPathParam = keyList?.map(id => data[id]).join(','); - key = viewElement.key && String(dataPathParam) || ''; - isNew = key; - if (!key) { - dispatch(new SetCollectingSelectionData(false)); - throw new Error('No value for key [' + viewElement.key + '] in list [' + property + ']'); - } } } @@ -410,7 +465,7 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async const [nsOrName, name] = cur.split(':', 1); const element = pViewSpecification.elements[cur] || pViewSpecification.elements[nsOrName] || pViewSpecification.elements[name]; if (!element && process.env.NODE_ENV === 'development' ) { - throw new Error('removeReadOnlyElements: Could not determine elment for data.'); + throw new Error('removeReadOnlyElements: Could not determine element for data.'); } if (element && element.config) { if (element.uiType === 'object') { @@ -436,7 +491,7 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async : data; // embed the first element list[key] - data = isNew + data = isNew || newData ? [data] : data; @@ -449,6 +504,10 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async } } + if (newData) { + dispatch(new UpdateNewData(null)); + } + if (isNew) { return dispatch(new ReplaceAction(`/configuration/${nodeId}/${vPath.replace(/\[\]$/i, `[${isNew}]`)}`)); // navigate to new element } diff --git a/sdnr/wt/odlux/apps/configurationApp/src/handlers/viewDescriptionHandler.ts b/sdnr/wt/odlux/apps/configurationApp/src/handlers/viewDescriptionHandler.ts index 39b47be84..4d361bf09 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/handlers/viewDescriptionHandler.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/handlers/viewDescriptionHandler.ts @@ -18,7 +18,7 @@ import { IActionHandler } from '../../../../framework/src/flux/action'; -import { UpdateViewDescription, UpdateOutputData } from '../actions/deviceActions'; +import { UpdateViewDescription, UpdateOutputData, UpdateNewData } from '../actions/deviceActions'; import { ViewSpecification } from '../models/uiModels'; export enum DisplayModeType { @@ -50,6 +50,7 @@ export type DisplaySpecification = { export interface IViewDescriptionState { vPath: string | null; displaySpecification: DisplaySpecification; + newData?: any; viewData: any; outputData?: any; } @@ -77,6 +78,11 @@ export const viewDescriptionHandler: IActionHandler<IViewDescriptionState> = (st ...state, outputData: action.outputData, }; + } else if (action instanceof UpdateNewData) { + state = { + ...state, + newData: action.newData, + }; } return state; }; diff --git a/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts b/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts index 7d9e63caf..c839f1c91 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/models/uiModels.ts @@ -174,11 +174,11 @@ export const isViewElementBoolean = (viewElement: ViewElement): viewElement is V }; export const isViewElementObject = (viewElement: ViewElement): viewElement is ViewElementObject => { - return viewElement && viewElement.uiType === 'object' && viewElement.isList === false; + return viewElement && viewElement.uiType === 'object' && !viewElement.isList; }; export const isViewElementList = (viewElement: ViewElement): viewElement is ViewElementList => { - return viewElement && viewElement.uiType === 'object' && viewElement.isList === true; + return viewElement && viewElement.uiType === 'object' && !!viewElement.isList; }; export const isViewElementObjectOrList = (viewElement: ViewElement): viewElement is ViewElementObject | ViewElementList => { diff --git a/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts b/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts index 07e263559..0fcd94567 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts @@ -143,8 +143,8 @@ class RestService { * @param data The data to be updated. * @returns The written data. */ - public setConfigData(path: string, data: any) { - return requestRestExt<{ [key: string]: any }>(path, { method: 'PUT', body: JSON.stringify(data) }); + public setConfigData(path: string, data: any, method: 'PUT' | 'POST' = 'PUT') { + return requestRestExt<{ [key: string]: any }>(path, { method, body: JSON.stringify(data) }); } public executeRpc(path: string, data: any) { diff --git a/sdnr/wt/odlux/apps/configurationApp/src/utilities/viewEngineHelper.ts b/sdnr/wt/odlux/apps/configurationApp/src/utilities/viewEngineHelper.ts index ad34c83b9..37f6876bd 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/utilities/viewEngineHelper.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/utilities/viewEngineHelper.ts @@ -10,6 +10,7 @@ import { isViewElementRpc, isViewElementChoice, ViewElementChoiceCase, + isViewElementObject, } from '../models/uiModels'; import { Module } from '../models/yang'; @@ -47,13 +48,13 @@ export const resolveVPath = (current: string, vPath: string): string => { return parts.join('/'); }; -export const splitVPath = (vPath: string, vPathParser : RegExp): [string, string?][] => { - const pathParts: [string, string?][] = []; +export const splitVPath = (vPath: string, vPathParser : RegExp): [string, (string | undefined | null)][] => { + const pathParts: [string, (string | undefined | null)][] = []; let partMatch: RegExpExecArray | null; if (vPath) do { partMatch = vPathParser.exec(vPath); if (partMatch) { - pathParts.push([partMatch[1], partMatch[2] || undefined]); + pathParts.push([partMatch[1], partMatch[2] || (partMatch[0].includes('[]') ? null : undefined)]); } } while (partMatch); return pathParts; @@ -321,4 +322,30 @@ export const filterViewElements = async (vPath: string, viewData: any, viewSpeci } return acc; }, Promise.resolve({ ...viewSpecification, elements: {} as { [key: string]: ViewElement } })); -};
\ No newline at end of file +}; + +export const createViewData = (namespace: string | null, viewSpecification: ViewSpecification, views: ViewSpecification[]) => Object.keys(viewSpecification.elements).reduce<{ [name: string]: any }>((acc, cur) => { + const elm = viewSpecification.elements[cur]; + let currentNamespace = namespace; + const key = elm.id; + if (elm.default) { + acc[key] = elm.default || ''; + } else if (elm.uiType === 'boolean') { + acc[key] = false; + } else if (elm.uiType === 'number') { + acc[key] = 0; + } else if (elm.uiType === 'string') { + acc[key] = ''; + } else if (isViewElementObject(elm)) { + const view = views[+elm.viewId]; + if (view) { + if (view.ns) { + currentNamespace = view.ns; + } + acc[key] = createViewData(currentNamespace, view, views); + } + } else if (isViewElementList(elm)) { + acc[key] = []; + } + return acc; +}, {});
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx index d7f59d61c..c8a518b9c 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx +++ b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx @@ -66,6 +66,7 @@ import AddIcon from '@mui/icons-material/Add'; import PostAdd from '@mui/icons-material/PostAdd'; import ArrowBack from '@mui/icons-material/ArrowBack'; import RemoveIcon from '@mui/icons-material/RemoveCircleOutline'; +import CheckIcon from '@mui/icons-material/Check'; import SaveIcon from '@mui/icons-material/Save'; import EditIcon from '@mui/icons-material/Edit'; import Tooltip from '@mui/material/Tooltip'; @@ -202,6 +203,7 @@ type ConfigurationApplicationComponentProps = RouteComponentProps & Connect<type type ConfigurationApplicationComponentState = { isNew: boolean; + isNewSubElement: boolean; editMode: boolean; canEdit: boolean; viewData: { [key: string]: any } | null; @@ -235,6 +237,7 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp this.state = { isNew: false, + isNewSubElement: false, canEdit: false, editMode: false, viewData: null, @@ -283,11 +286,14 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp static getDerivedStateFromProps(nextProps: ConfigurationApplicationComponentProps, prevState: ConfigurationApplicationComponentState & { [OldProps]: ConfigurationApplicationComponentProps }) { if (!prevState || !prevState[OldProps] || (prevState[OldProps].viewData !== nextProps.viewData)) { - const isNew: boolean = nextProps.vPath?.endsWith('[]') || false; + const isNew: boolean = nextProps.vPath?.includes('[]') || false; + const isNewSubElement: boolean = nextProps.vPath?.includes('[]') && !nextProps.vPath?.endsWith('[]') || false; + const state = { ...prevState, isNew: isNew, editMode: isNew, + isNewSubElement: isNewSubElement, viewData: nextProps.viewData || null, [OldProps]: nextProps, choices: nextProps.displaySpecification.displayMode === DisplayModeType.doNotDisplay @@ -543,7 +549,7 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp ? ( <div className={classes.section}> {sections.references.map(element => ( - <UIElementReference key={element.id} element={element} disabled={editMode || this.isPolicyViewElementForbidden(element, dataPath)} onOpenReference={(elm) => { this.navigate(`/${elm.id}`); }} /> + <UIElementReference key={element.id} element={element} disabled={!isNew && (editMode || this.isPolicyViewElementForbidden(element, dataPath))} onOpenReference={(elm) => { this.navigate(`/${elm.id}`); }} /> ))} </div> ) : null @@ -698,12 +704,12 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp ev.preventDefault(); let keyId = ''; if (listKeyProperty && listKeyProperty.split(' ').length > 1) { - keyId += listKeyProperty.split(' ').map(id => row[id]).join(','); + keyId += listKeyProperty.split(' ').map(id => encodeURIComponent(String(row[id]))).join(','); } else { - keyId = row[listKeyProperty]; + keyId = encodeURIComponent(String(row[listKeyProperty])); } if (listKeyProperty) { - navigate(`[${encodeURIComponent(keyId)}]`); // Do not navigate without key. + navigate(`[${keyId}]`); // Do not navigate without key. } }} ></SelectElementTable> ); @@ -774,11 +780,13 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp } private renderBreadCrumps() { - const { editMode } = this.state; + const { editMode, isNew, isNewSubElement } = this.state; const { displaySpecification, vPath, nodeId } = this.props; const pathParts = splitVPath(vPath!, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key + let lastPath = '/configuration'; let basePath = `/configuration/${nodeId}`; + return ( <div className={this.props.classes.header}> <div> @@ -827,7 +835,13 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp {this.state.editMode && ( <Fab color="secondary" aria-label="back-button" className={this.props.classes.fab} onClick={async () => { if (this.props.vPath) { - await this.props.reloadView(this.props.vPath); + if (isNewSubElement || isNew) { + const index = this.props.vPath.lastIndexOf('[]'); + const newVPath = this.props.vPath.substring(0, index + ( isNewSubElement ? 2 : 0 )); + this.props.history.replace(`/configuration/${nodeId}/${newVPath}`); + } else { + await this.props.reloadView(this.props.vPath); + } } this.setState({ editMode: false }); }} ><ArrowBack /></Fab> @@ -835,15 +849,21 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp { /* do not show edit if this is a list or it can't be edited */ displaySpecification.displayMode === DisplayModeType.displayAsObject && displaySpecification.viewSpecification.canEdit && (<div> <Fab color="secondary" aria-label={editMode ? 'save-button' : 'edit-button'} className={this.props.classes.fab} onClick={() => { - if (this.state.editMode) { + if (this.state.editMode && this.props.vPath) { // ensure only active choices will be contained const resultingViewData = this.collectData(displaySpecification.viewSpecification.elements); this.props.onUpdateData(this.props.vPath!, resultingViewData); + + const index = this.props.vPath.lastIndexOf('[]'); + const newVPath = this.props.vPath.substring(0, index + ( isNewSubElement ? 2 : 0 )); + this.props.history.replace(`/configuration/${nodeId}/${newVPath}`); } this.setState({ editMode: !editMode }); }}> - {editMode - ? <SaveIcon /> + { editMode + ? isNewSubElement + ? <CheckIcon /> + : <SaveIcon /> : <EditIcon /> } </Fab> diff --git a/sdnr/wt/odlux/apps/configurationApp/src/yang/whenParser.ts b/sdnr/wt/odlux/apps/configurationApp/src/yang/whenParser.ts index fa2968c9c..4956b13a9 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/yang/whenParser.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/yang/whenParser.ts @@ -3,6 +3,7 @@ enum WhenTokenType { OR = 'OR', NOT = 'NOT', EQUALS = 'EQUALS', + NOT_EQUALS = 'NOT_EQUALS', COMMA = 'COMMA', STRING = 'STRING', FUNCTION = 'FUNCTION', @@ -17,9 +18,31 @@ type Token = { value: string; }; -const isAlpha = (char: string) => /[a-z]/i.test(char); +const isAlpha = (char: string) => { + if (!char) return false; + const code = char.charCodeAt(0); + return (code >= 65 && code <= 90) || (code >= 97 && code <= 122); +}; + +const isAlphaNumeric = (char: string) => { + if (!char) return false; + const code = char.charCodeAt(0); + return ( + isAlpha(char) || + (code >= 48 && code <= 57) || + code === 95 || // underscore + code === 45 || // hyphen + code === 47 || // slash + code === 58 || // colon + code === 46 // dot + ); +}; -const isAlphaNumeric = (char: string) => /[A-Za-z0-9_\-/:\.]/i.test(char); +const isOperator = (char: string) => { + if (!char) return false; + const code = char.charCodeAt(0); + return code === 33 || code === 38 || code === 124 || code === 61; +}; const lex = (input: string) : Token[] => { let tokens = [] as any[]; @@ -110,6 +133,7 @@ const lex = (input: string) : Token[] => { continue; } + if (isAlphaNumeric(char)) { let value = ''; while (isAlphaNumeric(char)) { @@ -120,6 +144,36 @@ const lex = (input: string) : Token[] => { tokens.push({ type: WhenTokenType.IDENTIFIER, value }); continue; } + + if (isOperator(char)) { + let value = ''; + while (isOperator(char)) { + value += char; + char = input[++current]; + } + + switch (value) { + case '&&': + tokens.push({ type: WhenTokenType.AND }); + break; + case '||': + tokens.push({ type: WhenTokenType.OR }); + break; + case '!': + tokens.push({ type: WhenTokenType.NOT }); + break; + case '==': + tokens.push({ type: WhenTokenType.EQUALS }); + break; + case '!=': + tokens.push({ type: WhenTokenType.NOT_EQUALS }); + break; + default: + throw new TypeError(`I don't know what this operator is: ${value}`); + } + continue; + } + throw new TypeError(`I don't know what this character is: ${char}`); } return tokens; diff --git a/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts b/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts index 85eeb41a4..14e3468ac 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/yang/yangParser.ts @@ -491,7 +491,12 @@ export class YangParser { } public postProcess() { - + // process all type refs + this._typeRefToResolve.forEach(cb => { + try { cb(); } catch (error) { + console.warn(error.message); + } + }); /** * This is to fix the issue for sequential execution of modules based on their child and parent relationship * We are sorting the module object based on their augment status @@ -580,7 +585,7 @@ export class YangParser { const identity = module.identities[idKey]; if (identity.base != null) { const base = this.resolveIdentity(identity.base, module); - base.children?.push(identity); + base?.children?.push(identity); } else { baseIdentities.push(identity); } @@ -596,12 +601,6 @@ export class YangParser { } }); - this._typeRefToResolve.forEach(cb => { - try { cb(); } catch (error) { - console.warn(error.message); - } - }); - this._modulesToResolve.forEach(cb => { try { cb(); } catch (error) { console.warn(error.message); @@ -622,8 +621,11 @@ export class YangParser { } }); + const knownViews: ViewSpecification[] = []; // resolve readOnly const resolveReadOnly = (view: ViewSpecification, parentConfig: boolean) => { + if (knownViews.includes(view)) return; + knownViews.push(view); // update view config view.config = view.config && parentConfig; @@ -1622,4 +1624,4 @@ export class YangParser { : module.identities[identityName]; } -}
\ No newline at end of file +} diff --git a/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts b/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts index 948f2aada..f1965269f 100644 --- a/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts +++ b/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts @@ -1,4 +1,3 @@ - /** * ============LICENSE_START======================================================================== * ONAP : ccsdk feature sdnr wt odlux @@ -82,7 +81,7 @@ export const findWebUrisForGuiCutThroughAsyncAction = (networkElementIds: string networkElementIds.forEach(id => { const item = networkElements.rows.find((ne) => ne.id === id); if (item) { - if (item.status === 'Connected') { + if (item.status) { // if (item.coreModelCapability !== "Unsupported") { // element is connected and is added to search list, if it doesn't exist already @@ -118,7 +117,7 @@ export const findWebUrisForGuiCutThroughAsyncAction = (networkElementIds: string }); - if (elementsToSearch.length > 0 || notConnectedElements.length > 0 || unsupportedElements.length > 0) { + if (elementsToSearch.length > 0 || unsupportedElements.length > 0) { const result = await connectService.getAllWebUriExtensionsForNetworkElementListAsync(elementsToSearch); dispatcher(new AddWebUriList(result, notConnectedElements, unsupportedElements, prevFoundElements)); } @@ -138,4 +137,3 @@ export const updateCurrentViewAsyncAction = () => (dispatch: Dispatch, getState: return dispatch(connectionStatusLogReloadAction); } }; - diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx index 1ce8f0c3b..573ac931d 100644 --- a/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx +++ b/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx @@ -199,8 +199,9 @@ export class NetworkElementsListComponent extends React.Component<NetworkElement { property: 'port', title: 'Port', type: ColumnType.numeric }, { property: 'isRequired', title: 'Required', type: ColumnType.boolean }, { property: 'deviceType', title: 'Type', type: ColumnType.text }, - // { property: "coreModelCapability", title: "Core Model", type: ColumnType.text }, { property: 'deviceFunction', title: 'Function', type: ColumnType.text, width: '25%' }, + { property: "coreModelCapability", title: "Core Model", type: ColumnType.text }, + { property: "mountMethod", title: "Mount Method", type: ColumnType.text }, ]} idProperty="id" {...this.props.networkElementsActions} {...this.props.networkElementsProperties} asynchronus createContextMenu={rowData => { return this.getContextMenu(rowData); @@ -311,4 +312,4 @@ export class NetworkElementsListComponent extends React.Component<NetworkElement }; } -export const NetworkElementsList = withStyles(styles)(connect(mapProps, mapDispatch)(NetworkElementsListComponent)); +export const NetworkElementsList = withStyles(styles)(connect(mapProps, mapDispatch)(NetworkElementsListComponent));
\ No newline at end of file diff --git a/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts b/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts index 42d2824b9..71d62f94b 100644 --- a/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts +++ b/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts @@ -42,7 +42,7 @@ export const { appState.connect.networkElements.rows.forEach(element => { - if (element.status === 'Connected') { + if (element.status) { const webUri = webUris.find(item => item.id === element.id as string); if (webUri) { element.weburi = webUri.weburi; diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts index bb076c720..6a5d00dae 100644 --- a/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts +++ b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts @@ -41,6 +41,7 @@ export type NetworkElementConnection = { capability: string; }[]; }; + mountMethod?: string; }; diff --git a/sdnr/wt/odlux/apps/faultApp/src/components/dashboardHome.tsx b/sdnr/wt/odlux/apps/faultApp/src/components/dashboardHome.tsx index a3e32c42c..534a14336 100644 --- a/sdnr/wt/odlux/apps/faultApp/src/components/dashboardHome.tsx +++ b/sdnr/wt/odlux/apps/faultApp/src/components/dashboardHome.tsx @@ -153,7 +153,7 @@ class DashboardHome extends React.Component<HomeComponentProps> { let label = (data.datasets[tooltipItem.datasetIndex].labels && data.datasets[tooltipItem.datasetIndex].labels[ - tooltipItem.index + tooltipItem.index ]) || data.labels[tooltipItem.index] || ''; @@ -180,10 +180,12 @@ class DashboardHome extends React.Component<HomeComponentProps> { }, }, onClick: (event: MouseEvent, item: any) => { - if (item[0]) { - let connectionStatus = labels[item[0]._index] + ''; - this.props.navigateToApplication('connect', '/connectionStatus/' + connectionStatus); - } + setTimeout(() => { + if (item[0]) { + let connectionStatus = labels[item[0]._index] + ''; + this.props.navigateToApplication('connect', '/connectionStatus/' + connectionStatus); + } + }, 0); }, }; @@ -263,7 +265,7 @@ class DashboardHome extends React.Component<HomeComponentProps> { let label = (data.datasets[tooltipItem.datasetIndex].labels && data.datasets[tooltipItem.datasetIndex].labels[ - tooltipItem.index + tooltipItem.index ]) || data.labels[tooltipItem.index] || ''; @@ -290,10 +292,12 @@ class DashboardHome extends React.Component<HomeComponentProps> { }, }, onClick: (event: MouseEvent, item: any) => { - if (item[0]) { - let severity = alarmLabels[item[0]._index] + ''; - this.props.navigateToApplication('fault', '/alarmStatus/' + severity); - } + setTimeout(() => { + if (item[0]) { + let severity = alarmLabels[item[0]._index] + ''; + this.props.navigateToApplication('fault', '/alarmStatus/' + severity); + } + }, 0); }, }; |