예제 #1
0
  @Test
  public void test() throws IOException, URISyntaxException, SourceException, ReactorException {
    SchemaContext schema = StmtTestUtils.parseYangSources("/bugs/bug3799");
    assertNotNull(schema);

    Set<Module> modules = schema.getModules();
    assertNotNull(modules);
    assertEquals(1, modules.size());

    Module testModule = modules.iterator().next();
    Set<Module> subModules = testModule.getSubmodules();
    assertNotNull(subModules);
    assertEquals(1, subModules.size());

    Module testSubmodule = subModules.iterator().next();

    Set<NotificationDefinition> notifications = testSubmodule.getNotifications();
    assertNotNull(notifications);
    assertEquals(1, notifications.size());

    NotificationDefinition bazNotification = notifications.iterator().next();
    Collection<DataSchemaNode> childNodes = bazNotification.getChildNodes();
    assertNotNull(childNodes);
    assertEquals(1, childNodes.size());

    DataSchemaNode child = childNodes.iterator().next();
    assertTrue(child instanceof LeafSchemaNode);

    LeafSchemaNode leafBar = (LeafSchemaNode) child;
    String bar = leafBar.getQName().getLocalName();
    assertEquals("bar", bar);
  }
  public NetconfMessageTransformer(final SchemaContext schemaContext, final boolean strictParsing) {
    this.counter = new MessageCounter();
    this.schemaContext = schemaContext;
    parserFactory =
        DomToNormalizedNodeParserFactory.getInstance(
            XmlUtils.DEFAULT_XML_CODEC_PROVIDER, schemaContext, strictParsing);

    mappedRpcs = Maps.uniqueIndex(schemaContext.getOperations(), QNAME_FUNCTION);
    mappedNotifications = Multimaps.index(schemaContext.getNotifications(), QNAME_NOREV_FUNCTION);
  }
예제 #3
0
  public static List<ModuleBuilder> sortWithContext(
      final SchemaContext context, final ModuleBuilder... builders) {
    List<ModuleOrModuleBuilder> all =
        ModuleOrModuleBuilder.fromAll(context.getModules(), asList(builders));

    List<TopologicalSort.Node> sorted = sortInternal(all);
    // Cast to ModuleBuilder from Node if possible and return
    return Lists.transform(
        sorted,
        new Function<TopologicalSort.Node, ModuleBuilder>() {

          @Override
          public ModuleBuilder apply(final TopologicalSort.Node input) {
            if (input == null) {
              return null;
            }
            ModuleOrModuleBuilder moduleOrModuleBuilder = ((ModuleNodeImpl) input).getReference();
            if (moduleOrModuleBuilder.isModuleBuilder()) {
              return moduleOrModuleBuilder.getModuleBuilder();
            } else {
              return null;
            }
          }
        });
  }
예제 #4
0
  @BeforeClass
  public static void init()
      throws URISyntaxException, IOException, YangSyntaxErrorException,
          LeafRefYangSyntaxErrorException {

    final File resourceFile =
        new File(
            LeafRefContextTreeBuilderTest.class
                .getResource("/leafref-context-test/correct-modules/leafref-test2.yang")
                .toURI());

    final File resourceDir = resourceFile.getParentFile();

    final YangParserImpl parser = YangParserImpl.getInstance();
    context = parser.parseFile(resourceFile, resourceDir);

    final Set<Module> modules = context.getModules();
    for (final Module module : modules) {
      if (module.getName().equals("leafref-test2")) {
        rootMod = module;
      }
    }

    root = rootMod.getQNameModule();
    rootLeafRefContext = LeafRefContext.create(context);
  }
  private DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> buildContBuilderMod1(
      final String uri,
      final String rev,
      final String cont,
      final String contB,
      final String lf1,
      final String lf1_value) {
    final QName contQname = QName.create(uri, rev, cont);
    final QName contBQname = QName.create(uri, rev, contB);
    final QName lf1Qname = QName.create(contQname, lf1);

    final DataSchemaNode contSchemaNode = schemaContext.getDataChildByName(contQname);
    final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContainerNodeAttrBuilder =
        Builders.containerBuilder((ContainerSchemaNode) contSchemaNode);

    Preconditions.checkState(contSchemaNode instanceof ContainerSchemaNode);
    final List<DataSchemaNode> instanceLf1_m1 =
        ControllerContext.findInstanceDataChildrenByName(
            (DataNodeContainer) contSchemaNode, lf1Qname.getLocalName());
    final DataSchemaNode schemaLf1_m1 = Iterables.getFirst(instanceLf1_m1, null);

    dataContainerNodeAttrBuilder.withChild(
        Builders.leafBuilder((LeafSchemaNode) schemaLf1_m1).withValue(lf1_value).build());

    final DataSchemaNode contBSchemaNode =
        ((ContainerSchemaNode) contSchemaNode).getDataChildByName(contBQname);

    final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContainerB =
        Builders.containerBuilder((ContainerSchemaNode) contBSchemaNode);

    return dataContainerNodeAttrBuilder.withChild(dataContainerB.build());
  }
 private Multimap<String, Module> getStringModuleMap(SchemaContext delegate) {
   return Multimaps.index(
       delegate.getModules(),
       new Function<Module, String>() {
         @Override
         public String apply(Module input) {
           return input.getName();
         }
       });
 }
  @Override
  protected QName createQName(final String prefix, final String localName) {
    final String namespace = element.lookupNamespaceURI(prefix);
    Preconditions.checkArgument(namespace != null, "Failed to lookup prefix %s", prefix);

    final URI ns = URI.create(namespace);
    final Module module = schema.findModuleByNamespaceAndRevision(ns, null);
    Preconditions.checkArgument(module != null, "Namespace %s is not owned by a module", ns);
    return QName.create(module.getQNameModule(), localName);
  }
  /**
   * Filters SchemaContext for yang modules
   *
   * @param delegate original SchemaContext
   * @param rootModules modules (yang schemas) to be available and all their dependencies (modules
   *     importing rootModule and whole chain of their imports)
   * @param additionalModuleIds (additional) modules (yang schemas) to be available and whole chain
   *     of their imports
   */
  public FilteringSchemaContextProxy(
      final SchemaContext delegate,
      final Collection<ModuleId> rootModules,
      final Set<ModuleId> additionalModuleIds) {

    Preconditions.checkArgument(rootModules != null, "Base modules cannot be null.");
    Preconditions.checkArgument(additionalModuleIds != null, "Additional modules cannot be null.");

    final Builder<Module> filteredModulesBuilder = new Builder<>();

    final SetMultimap<URI, Module> nsMap =
        Multimaps.newSetMultimap(new TreeMap<URI, Collection<Module>>(), MODULE_SET_SUPPLIER);
    final SetMultimap<String, Module> nameMap =
        Multimaps.newSetMultimap(new TreeMap<String, Collection<Module>>(), MODULE_SET_SUPPLIER);

    ImmutableMap.Builder<ModuleIdentifier, String> identifiersToSourcesBuilder =
        ImmutableMap.builder();

    // preparing map to get all modules with one name but difference in revision
    final TreeMultimap<String, Module> nameToModulesAll = getStringModuleTreeMultimap();

    nameToModulesAll.putAll(getStringModuleMap(delegate));

    // in case there is a particular dependancy to view filteredModules/yang models
    // dependancy is checked for module name and imports
    processForRootModules(delegate, rootModules, filteredModulesBuilder);

    // adding additional modules
    processForAdditionalModules(delegate, additionalModuleIds, filteredModulesBuilder);

    filteredModulesBuilder.addAll(
        getImportedModules(
            Maps.uniqueIndex(delegate.getModules(), ModuleId.MODULE_TO_MODULE_ID),
            filteredModulesBuilder.build(),
            nameToModulesAll));

    /**
     * Instead of doing this on each invocation of getModules(), pre-compute it once and keep it
     * around -- better than the set we got in.
     */
    this.filteredModules = filteredModulesBuilder.build();

    for (final Module module : filteredModules) {
      nameMap.put(module.getName(), module);
      nsMap.put(module.getNamespace(), module);
      identifiersToSourcesBuilder.put(module, module.getSource());
    }

    namespaceToModules = ImmutableSetMultimap.copyOf(nsMap);
    nameToModules = ImmutableSetMultimap.copyOf(nameMap);
    identifiersToSources = identifiersToSourcesBuilder.build();
  }
 private void processForRootModules(
     SchemaContext delegate,
     final Collection<ModuleId> rootModules,
     Builder<Module> filteredModulesBuilder) {
   filteredModulesBuilder.addAll(
       Collections2.filter(
           delegate.getModules(),
           new Predicate<Module>() {
             @Override
             public boolean apply(@Nullable Module module) {
               return checkModuleDependency(module, rootModules);
             }
           }));
 }
 private void processForAdditionalModules(
     SchemaContext delegate,
     final Set<ModuleId> additionalModuleIds,
     Builder<Module> filteredModulesBuilder) {
   filteredModulesBuilder.addAll(
       Collections2.filter(
           delegate.getModules(),
           new Predicate<Module>() {
             @Override
             public boolean apply(@Nullable Module module) {
               return selectAdditionalModules(module, additionalModuleIds);
             }
           }));
 }
예제 #11
0
  public ConfigReader(
      final ConsoleIO console,
      final SchemaContext remoteSchemaContext,
      final CommandArgHandlerRegistry commandArgHandlerRegistry) {
    super(console, remoteSchemaContext);
    this.commandArgHandlerRegistry = commandArgHandlerRegistry;

    mappedModules = Maps.newHashMap();
    mappedModulesNamespace = Maps.newHashMap();
    for (final Module module : remoteSchemaContext.getModules()) {
      final QName moduleQName =
          QName.create(module.getNamespace(), module.getRevision(), module.getName());
      mappedModules.put(moduleQName.getLocalName(), moduleQName);
      mappedModulesNamespace.put(moduleQName.getNamespace(), moduleQName);
    }
  }
  /**
   * Write a child JSON node identifier, optionally prefixing it with the module name corresponding
   * to its namespace.
   *
   * @param schema Schema context
   * @param writer Output writer
   * @param qname Namespace/name tuple
   * @throws IOException when the writer reports it
   */
  final void writeChildJsonIdentifier(
      final SchemaContext schema, final JsonWriter writer, final QName qname) throws IOException {

    final StringBuilder sb = new StringBuilder();
    // Prepend module name if namespaces do not match
    final URI ns = qname.getNamespace();
    if (!ns.equals(getNamespace())) {
      final Module module = schema.findModuleByNamespaceAndRevision(ns, null);
      Preconditions.checkArgument(module != null, "Could not find module for namespace {}", ns);

      sb.append(module.getName());
      sb.append(':');
    }
    sb.append(qname.getLocalName());

    writer.name(sb.toString());
  }
  @Before
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);

    XMLUnit.setIgnoreWhitespace(true);
    XMLUnit.setIgnoreAttributeOrder(true);

    this.schemaContext = parseSchemas(getYangSchemas());
    schemaContext.getModules();
    final SchemaService schemaService = createSchemaService();

    final DOMStore operStore = InMemoryDOMDataStoreFactory.create("DOM-OPER", schemaService);
    final DOMStore configStore = InMemoryDOMDataStoreFactory.create("DOM-CFG", schemaService);

    final EnumMap<LogicalDatastoreType, DOMStore> datastores =
        new EnumMap<>(LogicalDatastoreType.class);
    datastores.put(LogicalDatastoreType.CONFIGURATION, configStore);
    datastores.put(LogicalDatastoreType.OPERATIONAL, operStore);

    ExecutorService listenableFutureExecutor =
        SpecialExecutors.newBlockingBoundedCachedThreadPool(16, 16, "CommitFutures");

    final ConcurrentDOMDataBroker cdb =
        new ConcurrentDOMDataBroker(datastores, listenableFutureExecutor);
    this.transactionProvider = new TransactionProvider(cdb, sessionIdForReporting);

    doAnswer(
            new Answer() {
              @Override
              public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
                final SourceIdentifier sId = (SourceIdentifier) invocationOnMock.getArguments()[0];
                final YangTextSchemaSource yangTextSchemaSource =
                    YangTextSchemaSource.delegateForByteSource(
                        sId, ByteSource.wrap("module test".getBytes()));
                return Futures.immediateCheckedFuture(yangTextSchemaSource);
              }
            })
        .when(sourceProvider)
        .getSource(any(SourceIdentifier.class));

    this.currentSchemaContext = new CurrentSchemaContext(schemaService, sourceProvider);
  }
public class NetconfMessageTransformer implements MessageTransformer<NetconfMessage> {

  public static final String MESSAGE_ID_PREFIX = "m";

  private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageTransformer.class);

  private static final Function<SchemaNode, QName> QNAME_FUNCTION =
      new Function<SchemaNode, QName>() {
        @Override
        public QName apply(final SchemaNode rpcDefinition) {
          return rpcDefinition.getQName();
        }
      };

  private static final Function<SchemaNode, QName> QNAME_NOREV_FUNCTION =
      new Function<SchemaNode, QName>() {
        @Override
        public QName apply(final SchemaNode notification) {
          return QNAME_FUNCTION.apply(notification).withoutRevision();
        }
      };
  private static final SchemaContext BASE_NETCONF_CTX;

  static {
    try {
      final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
      moduleInfoBackedContext.addModuleInfos(
          Lists.newArrayList(
              org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601
                  .$YangModuleInfoImpl.getInstance()));
      BASE_NETCONF_CTX = moduleInfoBackedContext.tryToCreateSchemaContext().get();
    } catch (final RuntimeException e) {
      LOG.error("Unable to prepare schema context for base netconf ops", e);
      throw new ExceptionInInitializerError(e);
    }
  }

  private static final Map<QName, RpcDefinition> MAPPED_BASE_RPCS =
      Maps.uniqueIndex(BASE_NETCONF_CTX.getOperations(), QNAME_FUNCTION);

  private final SchemaContext schemaContext;
  private final MessageCounter counter;
  private final Map<QName, RpcDefinition> mappedRpcs;
  private final Multimap<QName, NotificationDefinition> mappedNotifications;
  private final DomToNormalizedNodeParserFactory parserFactory;

  public NetconfMessageTransformer(final SchemaContext schemaContext, final boolean strictParsing) {
    this.counter = new MessageCounter();
    this.schemaContext = schemaContext;
    parserFactory =
        DomToNormalizedNodeParserFactory.getInstance(
            XmlUtils.DEFAULT_XML_CODEC_PROVIDER, schemaContext, strictParsing);

    mappedRpcs = Maps.uniqueIndex(schemaContext.getOperations(), QNAME_FUNCTION);
    mappedNotifications = Multimaps.index(schemaContext.getNotifications(), QNAME_NOREV_FUNCTION);
  }

  @Override
  public synchronized DOMNotification toNotification(final NetconfMessage message) {
    final Map.Entry<Date, XmlElement> stripped = stripNotification(message);
    final QName notificationNoRev;
    try {
      notificationNoRev =
          QName.create(stripped.getValue().getNamespace(), stripped.getValue().getName())
              .withoutRevision();
    } catch (final MissingNameSpaceException e) {
      throw new IllegalArgumentException(
          "Unable to parse notification " + message + ", cannot find namespace", e);
    }

    final Collection<NotificationDefinition> notificationDefinitions =
        mappedNotifications.get(notificationNoRev);
    Preconditions.checkArgument(
        notificationDefinitions.size() > 0,
        "Unable to parse notification %s, unknown notification. Available notifications: %s",
        notificationDefinitions,
        mappedNotifications.keySet());

    // FIXME if multiple revisions for same notifications are present, we should pick the most
    // recent. Or ?
    // We should probably just put the most recent notification versions into our map. We can expect
    // that the device sends the data according to the latest available revision of a model.
    final NotificationDefinition next = notificationDefinitions.iterator().next();

    // We wrap the notification as a container node in order to reuse the parsers and builders for
    // container node
    final ContainerSchemaNode notificationAsContainerSchemaNode =
        NetconfMessageTransformUtil.createSchemaForNotification(next);

    final Element element = stripped.getValue().getDomElement();
    final ContainerNode content;
    try {
      content =
          parserFactory
              .getContainerNodeParser()
              .parse(Collections.singleton(element), notificationAsContainerSchemaNode);
    } catch (IllegalArgumentException e) {
      throw new IllegalArgumentException(
          String.format("Failed to parse notification %s", element), e);
    }
    return new NetconfDeviceNotification(content, stripped.getKey());
  }

  private static final ThreadLocal<SimpleDateFormat> EVENT_TIME_FORMAT =
      new ThreadLocal<SimpleDateFormat>() {
        @Override
        protected SimpleDateFormat initialValue() {

          final SimpleDateFormat withMillis =
              new SimpleDateFormat(NetconfNotification.RFC3339_DATE_FORMAT_WITH_MILLIS_BLUEPRINT);

          return new SimpleDateFormat(NetconfNotification.RFC3339_DATE_FORMAT_BLUEPRINT) {
            private static final long serialVersionUID = 1L;

            @Override
            public Date parse(final String source) throws ParseException {
              try {
                return super.parse(source);
              } catch (ParseException e) {
                // In case of failure, try to parse with milliseconds
                return withMillis.parse(source);
              }
            }
          };
        }

        @Override
        public void set(final SimpleDateFormat value) {
          throw new UnsupportedOperationException();
        }
      };

  // FIXME move somewhere to util
  private static Map.Entry<Date, XmlElement> stripNotification(final NetconfMessage message) {
    final XmlElement xmlElement = XmlElement.fromDomDocument(message.getDocument());
    final List<XmlElement> childElements = xmlElement.getChildElements();
    Preconditions.checkArgument(
        childElements.size() == 2, "Unable to parse notification %s, unexpected format", message);

    final XmlElement eventTimeElement;
    final XmlElement notificationElement;

    if (childElements.get(0).getName().equals(EVENT_TIME)) {
      eventTimeElement = childElements.get(0);
      notificationElement = childElements.get(1);
    } else if (childElements.get(1).getName().equals(EVENT_TIME)) {
      eventTimeElement = childElements.get(1);
      notificationElement = childElements.get(0);
    } else {
      throw new IllegalArgumentException(
          "Notification payload does not contain " + EVENT_TIME + " " + message);
    }

    try {
      return new AbstractMap.SimpleEntry<>(
          EVENT_TIME_FORMAT.get().parse(eventTimeElement.getTextContent()), notificationElement);
    } catch (DocumentedException e) {
      throw new IllegalArgumentException(
          "Notification payload does not contain " + EVENT_TIME + " " + message);
    } catch (ParseException e) {
      LOG.warn(
          "Unable to parse event time from {}. Setting time to {}",
          eventTimeElement,
          NetconfNotification.UNKNOWN_EVENT_TIME,
          e);
      return new AbstractMap.SimpleEntry<>(
          NetconfNotification.UNKNOWN_EVENT_TIME, notificationElement);
    }
  }

  @Override
  public NetconfMessage toRpcRequest(SchemaPath rpc, final NormalizedNode<?, ?> payload) {
    // In case no input for rpc is defined, we can simply construct the payload here
    final QName rpcQName = rpc.getLastComponent();
    Map<QName, RpcDefinition> currentMappedRpcs = mappedRpcs;

    // Determine whether a base netconf operation is being invoked and also check if the device
    // exposed model for base netconf
    // If no, use pre built base netconf operations model
    final boolean needToUseBaseCtx = mappedRpcs.get(rpcQName) == null && isBaseRpc(rpcQName);
    if (needToUseBaseCtx) {
      currentMappedRpcs = MAPPED_BASE_RPCS;
    }

    Preconditions.checkNotNull(
        currentMappedRpcs.get(rpcQName),
        "Unknown rpc %s, available rpcs: %s",
        rpcQName,
        currentMappedRpcs.keySet());
    if (currentMappedRpcs.get(rpcQName).getInput() == null) {
      return new NetconfMessage(
          prepareDomResultForRpcRequest(rpcQName).getNode().getOwnerDocument());
    }

    Preconditions.checkNotNull(
        payload, "Transforming an rpc with input: %s, payload cannot be null", rpcQName);
    Preconditions.checkArgument(
        payload instanceof ContainerNode,
        "Transforming an rpc with input: %s, payload has to be a container, but was: %s",
        rpcQName,
        payload);

    // Set the path to the input of rpc for the node stream writer
    rpc = rpc.createChild(QName.create(rpcQName, "input").intern());
    final DOMResult result = prepareDomResultForRpcRequest(rpcQName);

    try {
      // If the schema context for netconf device does not contain model for base netconf
      // operations, use default pre build context with just the base model
      // This way operations like lock/unlock are supported even if the source for base model was
      // not provided
      writeNormalizedRpc(
          ((ContainerNode) payload),
          result,
          rpc,
          needToUseBaseCtx ? BASE_NETCONF_CTX : schemaContext);
    } catch (final XMLStreamException | IOException | IllegalStateException e) {
      throw new IllegalStateException("Unable to serialize " + rpc, e);
    }

    final Document node = result.getNode().getOwnerDocument();

    return new NetconfMessage(node);
  }

  private static boolean isBaseRpc(final QName rpc) {
    return rpc.getNamespace().equals(NETCONF_URI);
  }

  private DOMResult prepareDomResultForRpcRequest(final QName rpcQName) {
    final Document document = XmlUtil.newDocument();
    final Element rpcNS =
        document.createElementNS(
            NETCONF_RPC_QNAME.getNamespace().toString(), NETCONF_RPC_QNAME.getLocalName());
    // set msg id
    rpcNS.setAttribute(
        NetconfMessageTransformUtil.MESSAGE_ID_ATTR, counter.getNewMessageId(MESSAGE_ID_PREFIX));
    final Element elementNS =
        document.createElementNS(rpcQName.getNamespace().toString(), rpcQName.getLocalName());
    rpcNS.appendChild(elementNS);
    document.appendChild(rpcNS);
    return new DOMResult(elementNS);
  }

  private static void writeNormalizedRpc(
      final ContainerNode normalized,
      final DOMResult result,
      final SchemaPath schemaPath,
      final SchemaContext baseNetconfCtx)
      throws IOException, XMLStreamException {
    final XMLStreamWriter writer =
        NetconfMessageTransformUtil.XML_FACTORY.createXMLStreamWriter(result);
    try {
      try (final NormalizedNodeStreamWriter normalizedNodeStreamWriter =
          XMLStreamNormalizedNodeStreamWriter.create(writer, baseNetconfCtx, schemaPath)) {
        try (final OrderedNormalizedNodeWriter normalizedNodeWriter =
            new OrderedNormalizedNodeWriter(
                normalizedNodeStreamWriter, baseNetconfCtx, schemaPath)) {
          Collection<DataContainerChild<?, ?>> value = normalized.getValue();
          normalizedNodeWriter.write(value);
          normalizedNodeWriter.flush();
        }
      }
    } finally {
      try {
        writer.close();
      } catch (final Exception e) {
        LOG.warn("Unable to close resource properly", e);
      }
    }
  }

  @Override
  public synchronized DOMRpcResult toRpcResult(final NetconfMessage message, final SchemaPath rpc) {
    final NormalizedNode<?, ?> normalizedNode;
    final QName rpcQName = rpc.getLastComponent();
    if (NetconfMessageTransformUtil.isDataRetrievalOperation(rpcQName)) {
      final Element xmlData = NetconfMessageTransformUtil.getDataSubtree(message.getDocument());
      final ContainerSchemaNode schemaForDataRead =
          NetconfMessageTransformUtil.createSchemaForDataRead(schemaContext);
      final ContainerNode dataNode;

      try {
        dataNode =
            parserFactory
                .getContainerNodeParser()
                .parse(Collections.singleton(xmlData), schemaForDataRead);
      } catch (IllegalArgumentException e) {
        throw new IllegalArgumentException(
            String.format("Failed to parse data response %s", xmlData), e);
      }

      normalizedNode =
          Builders.containerBuilder()
              .withNodeIdentifier(
                  new YangInstanceIdentifier.NodeIdentifier(
                      NetconfMessageTransformUtil.NETCONF_RPC_REPLY_QNAME))
              .withChild(dataNode)
              .build();
    } else {

      Map<QName, RpcDefinition> currentMappedRpcs = mappedRpcs;

      // Determine whether a base netconf operation is being invoked and also check if the device
      // exposed model for base netconf
      // If no, use pre built base netconf operations model
      final boolean needToUseBaseCtx = mappedRpcs.get(rpcQName) == null && isBaseRpc(rpcQName);
      if (needToUseBaseCtx) {
        currentMappedRpcs = MAPPED_BASE_RPCS;
      }

      final RpcDefinition rpcDefinition = currentMappedRpcs.get(rpcQName);
      Preconditions.checkArgument(
          rpcDefinition != null, "Unable to parse response of %s, the rpc is unknown", rpcQName);

      // In case no input for rpc is defined, we can simply construct the payload here
      if (rpcDefinition.getOutput() == null) {
        Preconditions.checkArgument(
            XmlElement.fromDomDocument(message.getDocument())
                .getOnlyChildElementWithSameNamespaceOptionally("ok")
                .isPresent(),
            "Unexpected content in response of rpc: %s, %s",
            rpcDefinition.getQName(),
            message);
        normalizedNode = null;
      } else {
        final Element element = message.getDocument().getDocumentElement();
        try {
          normalizedNode =
              parserFactory
                  .getContainerNodeParser()
                  .parse(Collections.singleton(element), rpcDefinition.getOutput());
        } catch (IllegalArgumentException e) {
          throw new IllegalArgumentException(
              String.format("Failed to parse RPC response %s", element), e);
        }
      }
    }
    return new DefaultDOMRpcResult(normalizedNode);
  }

  private static class NetconfDeviceNotification implements DOMNotification, DOMEvent {
    private final ContainerNode content;
    private final SchemaPath schemaPath;
    private final Date eventTime;

    NetconfDeviceNotification(final ContainerNode content, final Date eventTime) {
      this.content = content;
      this.eventTime = eventTime;
      this.schemaPath = toPath(content.getNodeType());
    }

    @Nonnull
    @Override
    public SchemaPath getType() {
      return schemaPath;
    }

    @Nonnull
    @Override
    public ContainerNode getBody() {
      return content;
    }

    @Override
    public Date getEventTime() {
      return eventTime;
    }
  }
}
 @Override
 protected String prefixForNamespace(final URI namespace) {
   final Module module = context.findModuleByNamespaceAndRevision(namespace, null);
   return module == null ? null : module.getName();
 }
 @Override
 protected Module moduleForPrefix(final String prefix) {
   return context.findModuleByName(prefix, null);
 }