2 * Copyright © 2017 AT&T and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.transportpce.olm.service;
11 import com.google.common.base.Strings;
12 import com.google.common.util.concurrent.ListenableFuture;
14 import java.math.BigDecimal;
15 import java.math.RoundingMode;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.Optional;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.TimeoutException;
24 import java.util.stream.Collectors;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.transportpce.common.InstanceIdentifiers;
30 import org.opendaylight.transportpce.common.NetworkUtils;
31 import org.opendaylight.transportpce.common.Timeouts;
32 import org.opendaylight.transportpce.common.device.DeviceTransaction;
33 import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
34 import org.opendaylight.transportpce.common.mapping.PortMapping;
35 import org.opendaylight.transportpce.olm.power.PowerMgmt;
36 import org.opendaylight.transportpce.olm.util.OlmUtils;
37 import org.opendaylight.transportpce.olm.util.OtsPmHolder;
38 import org.opendaylight.transportpce.olm.util.RoadmLinks;
39 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev161014.RatioDB;
40 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.Interface;
41 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.InterfaceBuilder;
42 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.InterfaceKey;
43 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmLinkType;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.transport.interfaces.rev161014.Interface1;
47 import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.transport.interfaces.rev161014.Interface1Builder;
48 import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.transport.interfaces.rev161014.ots.container.Ots;
49 import org.opendaylight.yang.gen.v1.http.org.openroadm.optical.transport.interfaces.rev161014.ots.container.OtsBuilder;
50 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
51 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
52 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev170907.olm.get.pm.input.ResourceIdentifierBuilder;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkId;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkKey;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeKey;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNode;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.Link;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.CalculateSpanlossBaseInput;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.CalculateSpanlossBaseOutput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.CalculateSpanlossBaseOutputBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.CalculateSpanlossCurrentInput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.CalculateSpanlossCurrentOutput;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.CalculateSpanlossCurrentOutputBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.GetPmInput;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.GetPmInputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.GetPmOutput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.GetPmOutputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.ServicePowerResetInput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.ServicePowerResetOutput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.ServicePowerSetupInput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.ServicePowerSetupOutput;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.ServicePowerSetupOutputBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.ServicePowerTurndownInput;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.ServicePowerTurndownOutput;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.ServicePowerTurndownOutputBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.olm.rev170418.get.pm.output.Measurements;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.Mapping;
82 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
83 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
87 public class OlmPowerServiceImpl implements OlmPowerService {
88 private static final Logger LOG = LoggerFactory.getLogger(OlmPowerServiceImpl.class);
89 private static final String SUCCESS = "Success";
90 private static final String FAILED = "Failed";
91 private final DataBroker dataBroker;
92 private final PowerMgmt powerMgmt;
93 private final DeviceTransactionManager deviceTransactionManager;
94 private final PortMapping portMapping;
96 public OlmPowerServiceImpl(DataBroker dataBroker, PowerMgmt powerMgmt,
97 DeviceTransactionManager deviceTransactionManager, PortMapping portMapping) {
98 this.dataBroker = dataBroker;
99 this.powerMgmt = powerMgmt;
100 this.portMapping = portMapping;
101 this.deviceTransactionManager = deviceTransactionManager;
105 LOG.info("init ...");
108 public void close() {
109 LOG.info("close ...");
114 public GetPmOutput getPm(GetPmInput pmInput) {
115 GetPmOutputBuilder pmOutputBuilder = OlmUtils.pmFetch(pmInput, deviceTransactionManager);
116 return pmOutputBuilder.build();
120 public ServicePowerSetupOutput servicePowerSetup(ServicePowerSetupInput powerSetupInput) {
121 ServicePowerSetupOutputBuilder powerSetupOutput = new ServicePowerSetupOutputBuilder();
122 boolean successValPowerCalculation = powerMgmt.setPower(powerSetupInput);
124 if (successValPowerCalculation) {
125 powerSetupOutput.setResult(SUCCESS);
127 powerSetupOutput.setResult(FAILED);
129 return powerSetupOutput.build();
133 public ServicePowerTurndownOutput servicePowerTurndown(
134 ServicePowerTurndownInput powerTurndownInput) {
136 ServicePowerTurndownOutputBuilder powerTurnDownOutput = new ServicePowerTurndownOutputBuilder();
137 // TODO add flag or return failure instead of string
138 if (powerMgmt.powerTurnDown(powerTurndownInput)) {
139 powerTurnDownOutput.setResult(SUCCESS);
141 powerTurnDownOutput.setResult(FAILED);
143 return powerTurnDownOutput.build();
147 public CalculateSpanlossBaseOutput calculateSpanlossBase(CalculateSpanlossBaseInput spanlossBaseInput) {
149 LOG.info("CalculateSpanlossBase Request received for source type {}", spanlossBaseInput.getSrcType());
151 List<Link> networkLinks = getNetworkLinks();
152 if (networkLinks.isEmpty()) {
153 LOG.warn("Failed to get links form {} topology.", NetworkUtils.OVERLAY_NETWORK_ID);
154 return new CalculateSpanlossBaseOutputBuilder().setResult(FAILED).build();
157 if (! CalculateSpanlossBaseInput.SrcType.All.equals(spanlossBaseInput.getSrcType())) {
158 networkLinks = networkLinks.stream()
159 .filter(link -> link.getLinkId().equals(spanlossBaseInput.getLinkId()))
160 .collect(Collectors.toList());
163 List<RoadmLinks> roadmLinks = new ArrayList<>();
164 for (Link link : networkLinks) {
165 Link1 roadmLinkAugmentation = link.getAugmentation(Link1.class);
166 if (roadmLinkAugmentation == null) {
167 LOG.debug("Missing OpenRoadm link augmentation in link {} from {} topology.",
168 link.getLinkId().getValue(), NetworkUtils.OVERLAY_NETWORK_ID);
171 if (OpenroadmLinkType.ROADMTOROADM.equals(roadmLinkAugmentation.getLinkType())) {
172 // Only calculate spanloss for Roadm-to-Roadm links
173 RoadmLinks roadmLink = new RoadmLinks();
174 roadmLink.setSrcNodeId(link.getSource().getSourceNode().getValue());
175 roadmLink.setSrcTpId(link.getSource().getSourceTp().toString());
176 roadmLink.setDestNodeId(link.getDestination().getDestNode().getValue());
177 roadmLink.setDestTpid(link.getDestination().getDestTp().toString());
178 roadmLinks.add(roadmLink);
182 if (roadmLinks.isEmpty()) {
183 LOG.warn("Topology {} does not have any Roadm-to-Roadm links.", NetworkUtils.OVERLAY_NETWORK_ID);
184 return new CalculateSpanlossBaseOutputBuilder().setResult(FAILED).build();
187 boolean spanLossResult = getLinkSpanloss(roadmLinks);
188 CalculateSpanlossBaseOutputBuilder spanLossBaseBuilder = new CalculateSpanlossBaseOutputBuilder();
189 if (spanLossResult) {
190 spanLossBaseBuilder.setResult(SUCCESS);
191 return spanLossBaseBuilder.build();
193 LOG.warn("Spanloss calculation failed");
194 spanLossBaseBuilder.setResult(FAILED);
195 return spanLossBaseBuilder.build();
201 public CalculateSpanlossCurrentOutput calculateSpanlossCurrent(CalculateSpanlossCurrentInput input) {
202 LOG.info("calculateSpanlossCurrent Request received for all links in network model.");
203 List<Link> networkLinks = getNetworkLinks();
204 if (networkLinks.isEmpty()) {
205 LOG.warn("Failed to get links form {} topology.", NetworkUtils.OVERLAY_NETWORK_ID);
208 List<RoadmLinks> roadmLinks = new ArrayList<>();
209 for (Link link : networkLinks) {
210 Link1 roadmLinkAugmentation = link.getAugmentation(Link1.class);
211 if (roadmLinkAugmentation == null) {
212 LOG.debug("Missing OpenRoadm link augmentation in link {} from {} topology.",
213 link.getLinkId().getValue(), NetworkUtils.OVERLAY_NETWORK_ID);
216 if (OpenroadmLinkType.ROADMTOROADM.equals(roadmLinkAugmentation.getLinkType())) {
217 // Only calculate spanloss for Roadm-to-Roadm links
218 RoadmLinks roadmLink = new RoadmLinks();
219 roadmLink.setSrcNodeId(link.getSource().getSourceNode().toString());
220 roadmLink.setSrcTpId(link.getSource().getSourceTp().toString());
221 roadmLink.setDestNodeId(link.getDestination().getDestNode().toString());
222 roadmLink.setDestTpid(link.getDestination().getDestTp().toString());
223 roadmLinks.add(roadmLink);
227 if (roadmLinks.isEmpty()) {
228 LOG.warn("Topology {} does not have any Roadm-to-Roadm links.", NetworkUtils.OVERLAY_NETWORK_ID);
232 boolean spanLossResult = getLinkSpanloss(roadmLinks);
233 CalculateSpanlossCurrentOutputBuilder spanLossCurrentBuilder = new CalculateSpanlossCurrentOutputBuilder();
234 if (spanLossResult) {
235 spanLossCurrentBuilder.setResult(SUCCESS);
236 return spanLossCurrentBuilder.build();
238 LOG.error("Spanloss Current calculation failed");
239 spanLossCurrentBuilder.setResult(FAILED);
240 return spanLossCurrentBuilder.build();
245 public ServicePowerResetOutput servicePowerReset(ServicePowerResetInput input) {
250 private List<Link> getNetworkLinks() {
251 NetworkKey overlayTopologyKey = new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID));
253 InstanceIdentifier<Network1> networkIID = InstanceIdentifier.builder(Network.class, overlayTopologyKey)
254 .augmentation(Network1.class)
256 Optional<Network1> networkOptional;
257 try (ReadOnlyTransaction rtx = dataBroker.newReadOnlyTransaction()) {
258 //TODO change to constant from Timeouts class when it will be merged.
259 networkOptional = rtx.read(LogicalDatastoreType.CONFIGURATION, networkIID).get(Timeouts.DATASTORE_READ,
260 TimeUnit.MILLISECONDS).toJavaUtil();
261 } catch (InterruptedException | ExecutionException | TimeoutException e) {
262 LOG.warn("Read of {} topology failed", NetworkUtils.OVERLAY_NETWORK_ID);
263 return Collections.emptyList();
266 if (! networkOptional.isPresent()) {
267 LOG.warn("Network augmentation with links data is not present in {} topology.",
268 NetworkUtils.OVERLAY_NETWORK_ID);
269 return Collections.emptyList();
272 List<Link> networkLinks = networkOptional.get().getLink();
273 if (networkLinks == null || networkLinks.isEmpty()) {
274 LOG.warn("Links are not present in {} topology.", NetworkUtils.OVERLAY_NETWORK_ID);
275 return Collections.emptyList();
281 * This method retrieves OTS PM from current PM list by nodeId and TPId: Steps:
284 * 1. Get OTS interface name from port mapping by TPId 2. Call getPm RPC to get OTS PM
288 * @param nodeId Node-id of the NE.
289 * @param tpID Termination point Name.
290 * @param pmName PM name which need to be retrieved
291 * @return reference to OtsPmHolder
293 private OtsPmHolder getPmMeasurements(String nodeId, String tpID, String pmName) {
294 String realNodeId = getRealNodeId(nodeId);
295 Mapping mapping = portMapping.getMapping(realNodeId, tpID);
296 if (mapping == null) {
299 GetPmInput getPmInput = new GetPmInputBuilder().setNodeId(realNodeId)
300 .setResourceType(ResourceTypeEnum.Interface).setGranularity(PmGranularity._15min)
301 .setResourceIdentifier(
302 new ResourceIdentifierBuilder().setResourceName(mapping.getSupportingOts()).build())
304 GetPmOutput otsPmOutput = getPm(getPmInput);
306 if (otsPmOutput == null) {
307 LOG.info("OTS PM not found for NodeId: {} TP Id:{} PMName:{}", realNodeId, tpID, pmName);
311 for (Measurements measurement : otsPmOutput.getMeasurements()) {
312 if (pmName.equals(measurement.getPmparameterName())) {
313 return new OtsPmHolder(pmName, Double.parseDouble(measurement.getPmparameterValue()),
314 mapping.getSupportingOts());
317 } catch (NumberFormatException e) {
318 LOG.warn("Unable to get PM for NodeId: {} TP Id:{} PMName:{}", realNodeId, tpID, pmName, e);
324 * This method Sets Spanloss on A-End and Z-End OTS interface: Steps:
327 * 1. Read existing interface details
332 * @param nodeId nodeId of NE on which spanloss need to be updated
333 * @param interfaceName OTS interface for NE on which spanloss is cacluated
334 * @param spanLoss calculated spanloss value
335 * @param direction for which spanloss is calculated.It can be either Tx or Rx
338 private boolean setSpanLoss(String nodeId, String interfaceName, BigDecimal spanLoss, String direction) {
339 String realNodeId = getRealNodeId(nodeId);
340 LOG.info("Setting Spanloss in device for {}, InterfaceName: {}", realNodeId, interfaceName);
341 InstanceIdentifier<Interface> interfacesIID = InstanceIdentifier.create(OrgOpenroadmDevice.class)
342 .child(Interface.class, new InterfaceKey(interfaceName));
343 com.google.common.base.Optional<Interface> interfaceObject;
345 Future<Optional<DeviceTransaction>> deviceTxFuture =
346 deviceTransactionManager.getDeviceTransaction(realNodeId);
347 java.util.Optional<DeviceTransaction> deviceTxOpt = deviceTxFuture.get();
348 DeviceTransaction deviceTx;
349 if (deviceTxOpt.isPresent()) {
350 deviceTx = deviceTxOpt.get();
352 LOG.error("Device transaction for device {} was not found!", nodeId);
355 interfaceObject = deviceTx.read(LogicalDatastoreType.CONFIGURATION, interfacesIID).get();
356 BigDecimal initialSpanloss = new BigDecimal(0);
357 RatioDB spanLossRx = new RatioDB(initialSpanloss);
358 RatioDB spanLossTx = new RatioDB(initialSpanloss);
359 if (interfaceObject.isPresent()) {
360 Interface intf = interfaceObject.get();
361 InterfaceBuilder interfaceBuilder = new InterfaceBuilder(intf);
362 OtsBuilder otsBuilder = new OtsBuilder();
363 if (intf.getAugmentation(Interface1.class) != null
364 && intf.getAugmentation(Interface1.class).getOts() != null) {
365 Ots ots = intf.getAugmentation(Interface1.class).getOts();
366 otsBuilder.setFiberType(ots.getFiberType());
367 spanLossRx = ots.getSpanLossReceive();
368 spanLossTx = ots.getSpanLossTransmit();
370 spanLossRx = new RatioDB(spanLoss);
371 spanLossTx = new RatioDB(spanLoss);
373 Interface1Builder intf1Builder = new Interface1Builder();
374 if (direction.equals("TX")) {
375 otsBuilder.setSpanLossTransmit(new RatioDB(spanLoss));
376 otsBuilder.setSpanLossReceive(spanLossRx);
378 otsBuilder.setSpanLossTransmit(spanLossTx).setSpanLossReceive(new RatioDB(spanLoss));
380 interfaceBuilder.addAugmentation(Interface1.class, intf1Builder.setOts(otsBuilder.build()).build());
381 deviceTx.put(LogicalDatastoreType.CONFIGURATION, interfacesIID, interfaceBuilder.build());
382 ListenableFuture<Void> submit =
383 deviceTx.submit(Timeouts.DEVICE_WRITE_TIMEOUT, Timeouts.DEVICE_WRITE_TIMEOUT_UNIT);
385 LOG.info("Spanloss Value update completed successfully");
388 } catch (InterruptedException | ExecutionException e) {
389 LOG.warn("Unable to set spanloss", e);
395 * This method calculates Spanloss by TranmistPower - Receive Power Steps:
398 * 1. Read PM measurement
401 * 2. Set Spanloss value for interface
403 * @param roadmLinks reference to list of RoadmLinks
406 private boolean getLinkSpanloss(List<RoadmLinks> roadmLinks) {
407 LOG.info("Executing GetLinkSpanLoss");
408 BigDecimal spanLoss = new BigDecimal(0);
409 for (int i = 0; i < roadmLinks.size(); i++) {
411 OtsPmHolder srcOtsPmHoler = getPmMeasurements(roadmLinks.get(i).getSrcNodeId(),
412 roadmLinks.get(i).getSrcTpId(), "OpticalPowerOutput");
413 OtsPmHolder destOtsPmHoler = getPmMeasurements(roadmLinks.get(i).getDestNodeId(),
414 roadmLinks.get(i).getDestTpid(), "OpticalPowerInput");
415 spanLoss = new BigDecimal(srcOtsPmHoler.getOtsParameterVal() - destOtsPmHoler.getOtsParameterVal())
416 .setScale(0, RoundingMode.HALF_UP);
417 LOG.info("Spanloss Calculated as :" + spanLoss + "=" + srcOtsPmHoler.getOtsParameterVal() + "-"
418 + destOtsPmHoler.getOtsParameterVal());
419 if (spanLoss.doubleValue() < 28 && spanLoss.doubleValue() > 0) {
420 if (!setSpanLoss(roadmLinks.get(i).getSrcNodeId(), srcOtsPmHoler.getOtsInterfaceName(), spanLoss,
422 LOG.info("Setting spanLoss failed for " + roadmLinks.get(i).getSrcNodeId());
425 if (!setSpanLoss(roadmLinks.get(i).getDestNodeId(), destOtsPmHoler.getOtsInterfaceName(), spanLoss,
427 LOG.info("Setting spanLoss failed for " + roadmLinks.get(i).getDestNodeId());
435 private String getRealNodeId(String mappedNodeId) {
436 KeyedInstanceIdentifier<Node, NodeKey> mappedNodeII =
437 InstanceIdentifiers.OVERLAY_NETWORK_II.child(Node.class, new NodeKey(new NodeId(mappedNodeId)));
438 com.google.common.base.Optional<Node> realNode;
439 try (ReadOnlyTransaction readOnlyTransaction = dataBroker.newReadOnlyTransaction()) {
440 realNode = readOnlyTransaction.read(LogicalDatastoreType.CONFIGURATION, mappedNodeII).get();
441 } catch (InterruptedException | ExecutionException e) {
442 LOG.error(e.getMessage(), e);
443 throw new IllegalStateException(e);
445 if (!realNode.isPresent() || realNode.get().getSupportingNode() == null) {
446 throw new IllegalArgumentException(
447 String.format("Could not find node %s, or supporting node is not present", mappedNodeId));
449 List<SupportingNode> collect = realNode.get().getSupportingNode().stream()
450 .filter(node -> node.getNetworkRef() != null
451 && NetworkUtils.UNDERLAY_NETWORK_ID.equals(node.getNetworkRef().getValue())
452 && node.getNodeRef() != null && !Strings.isNullOrEmpty(node.getNodeRef().getValue()))
453 .collect(Collectors.toList());
454 if (collect.isEmpty() || collect.size() > 1) {
455 throw new IllegalArgumentException(String.format("Invalid support node count [%d] was found for node %s",
456 collect.size(), mappedNodeId));
458 return collect.iterator().next().getNodeRef().getValue();