summaryrefslogtreecommitdiffstats
path: root/netconf/restconf/restconf-nb-bierman02
diff options
context:
space:
mode:
Diffstat (limited to 'netconf/restconf/restconf-nb-bierman02')
-rw-r--r--netconf/restconf/restconf-nb-bierman02/pom.xml214
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaExportContentYangBodyWriter.java57
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaExportContentYinBodyWriter.java51
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaRetrievalService.java30
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaRetrievalServiceImpl.java92
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/Draft02.java67
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestConnector.java17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfConstants.java15
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfNormalizedNodeWriter.java18
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfService.java435
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/package-info.java9
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/AbstractIdentifierAwareJaxRsProvider.java63
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriter.java305
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/JsonNormalizedNodeBodyReader.java174
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/JsonToPatchBodyReader.java486
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeContext.java68
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeJsonBodyWriter.java200
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeXmlBodyWriter.java181
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/PatchJsonBodyWriter.java130
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/PatchXmlBodyWriter.java143
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfApplication.java72
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfCompositeWrapper.java128
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfDelegatingNormalizedNodeWriter.java51
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfDocumentedExceptionMapper.java430
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/StringModuleInstanceIdentifierCodec.java62
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/UnsupportedFormatException.java29
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/WriterParameters.java49
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlNormalizedNodeBodyReader.java200
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlToPatchBodyReader.java313
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/package-info.java8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/api/JSONRestconfService.java99
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/api/RestConfConfig.java30
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BatchedExistenceCheck.java90
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/Bierman02RestConfWiring.java75
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java1277
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/ControllerContext.java1006
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizationException.java16
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizationOperation.java526
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizer.java81
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/JSONRestconfServiceImpl.java291
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/NormalizedDataPrunner.java143
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/PutResult.java51
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/QueryParametersParser.java69
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestCodec.java380
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java1546
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfProviderImpl.java111
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/StatisticsRestconfServiceWrapper.java301
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Config.java81
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Delete.java69
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Get.java68
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Operational.java38
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Post.java68
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Put.java67
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/RestConnectorRuntimeMXBean.java16
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Rpcs.java67
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/package-info.java13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/package-info.java8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/web/WebInitializer.java60
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractCommonSubscriber.java142
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractNotificationsData.java153
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractQueryParams.java161
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/BaseListenerInterface.java47
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/Event.java77
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/EventBusChangeRecorder.java53
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/EventType.java15
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapter.java425
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerAdapter.java181
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/Notificator.java230
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServer.java152
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServerHandler.java185
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServerInitializer.java31
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilder.java20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilder.java29
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilder.java42
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/resources/OSGI-INF/blueprint/restconf-config.xml78
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/main/yang/ietf-restconf@2013-10-19.yang689
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/md/sal/rest/common/TestRestconfUtils.java189
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/InstanceIdentifierTypeLeafTest.java55
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java127
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java186
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReaderMountPoint.java151
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyWriter.java65
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReader.java165
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReaderMountPoint.java172
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java287
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java220
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyWriter.java58
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReader.java137
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReaderMountPoint.java133
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java281
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIdentityrefTest.java22
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithDataFromSeveralModulesTest.java21
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java228
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonIdentityrefToNnTest.java68
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonLeafrefToNnTest.java58
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonToNnTest.java334
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnJsonChoiceCaseTest.java181
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonLeafrefType.java107
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonWithAugmentTest.java70
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnInstanceIdentifierToXmlTest.java250
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlTest.java407
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithChoiceTest.java108
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithDataFromSeveralModulesTest.java144
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bierman02RestConfWiringTest.java54
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java432
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug3595Test.java53
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug8072Test.java71
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java150
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java68
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CutDataToCorrectDepthTest.java388
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java94
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java71
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java62
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ExpressionParserTest.java171
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java344
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java532
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java260
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java21
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java38
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java96
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java52
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java742
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java182
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java135
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java220
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java831
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java147
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java168
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java306
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java258
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java172
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java163
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java21
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java30
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlAndDataSchemaLoader.java42
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModule.java127
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModuleTest.java35
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java130
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java92
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStreamTest.java132
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java22
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriterTest.java343
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/restconf/impl/InstanceIdentifierCodecImplTest.java99
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java220
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerTest.java206
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilderTest.java23
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleBuilderTest.java70
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilderTest.java28
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilderTest.java49
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/json/dataa.json7
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/json/datab.json7
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/xml/dataa.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/xml/datab.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/augment-main-a.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/augment-main-b.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/main.yang10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/opendaylight-inventory.yang19
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang39
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/sal-remote@2014-01-14.yang98
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/decoding-exception/yang/number.yang17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-container.json16
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-container.xml12
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-leaf.json15
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-leaf.xml11
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/yang/equal-data-node-names.yang18
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/foo-xml-test/foo.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/foo-xml-test/yang/foo.yang18
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/make-toast-rpc-input.json7
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data-rpc-input.json10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data-rpc-input.xml8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data2.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data3.xml4
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data4.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data5.xml8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data6.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data7.xml8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-module/test-module.yang101
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testCont1Data.json6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testCont1DataPatch.json20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testData.json92
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testData.xml120
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ex-vlan.yang47
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/iana-if-type.yang1517
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ietf-interfaces@2013-07-04.yang673
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ietf-yang-types@2013-05-16.yang471
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/sal-remote@2014-01-14.yang98
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/simple-nodes.yang80
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/subscribe-to-notification.yang18
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/toaster.yang197
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/iid-value.yang23
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHMergeOperationOnContainer.json43
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHMergeOperationOnList.json32
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHSimpleLeafValue.json17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdata.json35
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataCompleteTargetInURI.json44
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json31
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataValueMissing.json13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataValueNotSupported.json20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_augment_choice_container.json5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_augment_container.json5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_sub_container.json5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsondata.json14
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsondata_leaf_list.json7
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/bug7933.xml9
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlDataFindBarContainer.xml10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlDataFindFooContainer.xml10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdata.xml28
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml35
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml44
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml44
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml35
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataValueMissing.xml16
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml23
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_augment_choice_container.xml3
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_augment_container.xml3
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_sub_container.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmldata.xml10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmldata_leaf_list.xml8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-augment-module.yang21
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-module-leaf-list.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-module.yang63
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/bar-module.yang11
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/foo-module.yang11
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/instance-identifier-module.yang13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/instance-identifier-patch-module.yang47
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-inet-types.yang418
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-restconf-monitoring@2017-01-26.yang149
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-yang-library@2016-06-21.yang208
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-yang-types.yang417
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/invoke-rpc-module.yang30
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/json/rpc-input.json7
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/json/rpc-output.json7
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/xml/rpc-input.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/xml/rpc-output.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/array-with-null.json5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/empty-data.json6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/empty-data1.json5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/identity-module.yang10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/identityref-module.yang39
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/json/data.json10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/invalid-uri-character-in-value.json6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/augment-leafref-module.yang18
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/json/data.json7
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/leafref-module.yang24
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/multiple-items-in-list.json26
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/multiple-leaflist-items.json5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-container-yang/simple-container.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-container.json15
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/1/simple-list1.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/2/simple-list2.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/3/multiple-items.yang24
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/4/array-with-null.yang26
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list.json17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/unsupported-json-format.json1
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level1.json8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level2.json9
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level3.json3
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/augmented-jukebox@2016-05-05.yang16
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/example-jukebox@2015-04-04.yang243
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-inet-types.yang418
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-restconf-monitoring@2017-01-26.yang149
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-yang-library@2016-06-21.yang208
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-yang-types.yang417
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/json/jsondata.json8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/xml/xmldata.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/yang/leafref-module.yang54
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/yang/referenced-module.yang23
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-create.json55
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-del.json31
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-create.json31
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-del.json23
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-update.json31
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-update.json57
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-create.json13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-del.json13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-update.json13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/iana-if-type.yang1517
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-inet-types.yang418
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-interfaces@2013-07-04.yang673
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-restconf-monitoring@2017-01-26.yang149
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-restconf@2013-10-19.yang684
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-yang-library@2016-06-21.yang208
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-yang-types.yang417
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module1.yang12
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module2.yang11
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module3.yang5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/iana-if-type.yang1517
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-inet-types.yang418
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-interfaces@2013-07-04.yang673
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-restconf-monitoring@2017-01-26.yang149
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-restconf@2013-10-19.yang684
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-yang-library@2016-06-21.yang208
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-yang-types.yang417
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/module1-behind-mount-point.yang10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/module2-behind-mount-point.yang9
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module1.yang12
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module2.yang11
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module3.yang5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/mount-point-1.yang11
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/mount-points/mount-point-1.yang11
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/mount-points/mount-point-2.yang8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/nested-module.yang69
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/ietf-inet-types.yang418
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/ietf-yang-types.yang417
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/mount-point-1.yang11
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-container-modules/restconf-module-with-illegal-container-modules.yang685
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-list-module/restconf-module-with-illegal-list-module.yang684
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-container-modules/restconf-module-with-missing-container-modules.yang639
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-list-module/restconf-module-with-missing-list-module.yang650
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-inet-types.yang418
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-restconf@2013-10-19.yang684
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-yang-library@2016-06-21.yang208
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-yang-types.yang417
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/multiple-nodes/multiple-nodes.yang17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-container.yang22
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-leaf.yang18
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-leaflist.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-list.yang22
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/xml/data.xml16
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/yang.yang30
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/choice.yang125
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_case_defined_without_case.xml4
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_container.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_leaflist.xml4
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_list.xml8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_more_choices_same_level.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml7
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_no_first_case.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_random_level.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_three_choices_same_level.xml13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_various_path_err.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/data-of-several-modules/yang/module1.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/data-of-several-modules/yang/module2.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/identityref/identity-module.yang10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/identityref/identityref-module.yang21
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/invalid-top-level-element/invalid-top-level-element.yang13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/cont-augment-module.yang39
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/main-module.yang50
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml7
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_from_leafref_to_leafref.xml4
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml4
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_ref_to_not_leaf.xml4
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/list/list-types-module274
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/simple-data-types.yang278
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/xml/bad-data.xml3
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/xml/data.xml71
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/simple-yang-types.yang57
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/awaited_output_data.json72
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/awaited_output_empty_data.json49
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/data.xml63
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/empty_data.xml40
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/choice/module-with-choice.yang25
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/data-of-several-modules/yang/module1.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/data-of-several-modules/yang/module2.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/aug-referenced-elements-module.yang18
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/eferenced-elements-module.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/rinstance-identifier-module.yang16
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/yang/basic-module.yang111
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/yang/referenced-module.yang10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/normalize-node/yang/normalize-node-module14
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-inet-types.yang418
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-restconf-monitoring@2017-01-26.yang149
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-yang-library@2016-06-21.yang208
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-yang-types.yang417
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/notifi-module.yang49
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/subscribe-to-notification.yang18
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/toaster.yang200
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/xml/output/data_change_notification_toaster_status_DOWN.xml13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/xml/output/data_change_notification_toaster_status_NUMBER.xml13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/ordered/by/user/ordered-by-user-example.yang44
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/invoke-rpc-module.yang26
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/mount-point.yang17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/parser-identifier-test-included.yang23
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/parser-identifier-test.yang40
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/test-module.yang9
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces.json10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces2.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.json12
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.xml8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path2.xml7
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_interface_absolute_path.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_patch.json22
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-inet-types.yang418
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-restconf-monitoring@2017-01-26.yang149
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-restconf@2017-01-26.yang279
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-yang-library@2016-06-21.yang208
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-yang-types.yang417
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/deserializer/deserializer-test-included.yang22
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/deserializer/deserializer-test.yang90
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/list-test.yang39
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/serializer/serializer-test-included.yang22
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/serializer/serializer-test.yang86
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/streams/sal-remote@2014-01-14.yang112
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/streams/toaster.yang197
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/test-mount-point/yang/test-interface.yang30
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/test-mount-point/yang/test-interface2.yang27
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/block-data.xml4
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/data2.xml4
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface.xml8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface2.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface3.xml6
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/yang1/test-interface.yang49
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/yang2/test-interface2.yang27
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/varioustest/xmldata.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-container-yang/data-container.yang35
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-container.xml14
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list-yang/data-container.yang28
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list-yang/data-list.yang22
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list.xml21
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-nmspc-in-attributes.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-of-several-modules/yang/module1.yang16
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-of-several-modules/yang/module2.yang17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/empty-data.xml8
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/identity-module.yang10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/identityref-module.yang21
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-element.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml5
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/general-module.yang14
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/identity-module.yang10
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/identityref-module.yang20
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/leafref/leafref-module61
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/leafref/xml/data.xml8
432 files changed, 53162 insertions, 0 deletions
diff --git a/netconf/restconf/restconf-nb-bierman02/pom.xml b/netconf/restconf/restconf-nb-bierman02/pom.xml
new file mode 100644
index 0000000..f560d00
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/pom.xml
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-parent</artifactId>
+ <version>3.0.5</version>
+ </parent>
+
+ <groupId>org.onap.ccsdk.odl-legacy</groupId>
+ <artifactId>restconf-nb-bierman02</artifactId>
+ <version>1.0.0</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.annotation</groupId>
+ <artifactId>javax.annotation-api</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.guicedee.services</groupId>
+ <artifactId>javax.inject</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>restconf-common-models</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>restconf-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.inject</groupId>
+ <artifactId>jersey-hk2</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-dom-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-dom-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-codec-http</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-codec-gson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-codec-xml</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-export</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.binding.model.ietf</groupId>
+ <artifactId>rfc6991-ietf-inet-types</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.binding.model.ietf</groupId>
+ <artifactId>rfc6991-ietf-yang-types</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>net.java.dev.stax-utils</groupId>
+ <artifactId>stax-utils</artifactId>
+ <exclusions>
+ <exclusion>
+ <!-- JSR173 ships with JRE by default -->
+ <groupId>com.bea.xml</groupId>
+ <artifactId>jsr173-ri</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20131018</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.aaa.web</groupId>
+ <artifactId>web-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.aaa.web</groupId>
+ <artifactId>servlet-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.aaa</groupId>
+ <artifactId>aaa-filterchain</artifactId>
+ </dependency>
+
+ <!-- Testing Dependencies -->
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.aaa</groupId>
+ <artifactId>aaa-shiro-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>testutils</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-test-utils</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-dom-adapter</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.skyscreamer</groupId>
+ <artifactId>jsonassert</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.aaa.web</groupId>
+ <artifactId>testutils</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.infrautils</groupId>
+ <artifactId>inject.guice.testutils</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-test-util</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>MD SAL Restconf Connector</Bundle-Name>
+ <Private-Package>org.opendaylight.netconf.sal.rest.*,
+ org.opendaylight.netconf.sal.restconf.rpc.*,
+ org.opendaylight.netconf.sal.restconf.impl.*,
+ org.opendaylight.netconf.md.sal.rest.common.*,
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.rest.connector.rev140724.*,
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/netconf.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/netconf.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://git.opendaylight.org/gerrit/gitweb?p=netconf.git;a=summary</url>
+ </scm>
+</project>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaExportContentYangBodyWriter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaExportContentYangBodyWriter.java
new file mode 100644
index 0000000..c377650
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaExportContentYangBodyWriter.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.md.sal.rest.schema;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.concurrent.ExecutionException;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import org.opendaylight.restconf.common.schema.SchemaExportContext;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+
+@Provider
+@Produces({ YangConstants.RFC6020_YANG_MEDIA_TYPE })
+public class SchemaExportContentYangBodyWriter implements MessageBodyWriter<SchemaExportContext> {
+
+ @Override
+ public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+ final MediaType mediaType) {
+ return type.equals(SchemaExportContext.class);
+ }
+
+ @Override
+ public long getSize(final SchemaExportContext context, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public void writeTo(final SchemaExportContext context, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream) throws IOException,
+ WebApplicationException {
+ final RevisionSourceIdentifier sourceId = RevisionSourceIdentifier.create(context.getModule().getName(),
+ context.getModule().getQNameModule().getRevision());
+ final YangTextSchemaSource yangTextSchemaSource;
+ try {
+ yangTextSchemaSource = context.getSourceProvider().getSource(sourceId).get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new WebApplicationException("Unable to retrieve source from SourceProvider.", e);
+ }
+ yangTextSchemaSource.copyTo(entityStream);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaExportContentYinBodyWriter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaExportContentYinBodyWriter.java
new file mode 100644
index 0000000..9f4f8be
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaExportContentYinBodyWriter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.md.sal.rest.schema;
+
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import javax.xml.stream.XMLStreamException;
+import org.opendaylight.restconf.common.schema.SchemaExportContext;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.model.export.YinExportUtils;
+
+@Provider
+@Produces({ YangConstants.RFC6020_YIN_MEDIA_TYPE })
+public class SchemaExportContentYinBodyWriter implements MessageBodyWriter<SchemaExportContext> {
+
+ @Override
+ public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+ final MediaType mediaType) {
+ return type.equals(SchemaExportContext.class);
+ }
+
+ @Override
+ public long getSize(final SchemaExportContext context, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public void writeTo(final SchemaExportContext context, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream) throws
+ WebApplicationException {
+ try {
+ YinExportUtils.writeModuleAsYinText(context.getModule(), entityStream);
+ } catch (final XMLStreamException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaRetrievalService.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaRetrievalService.java
new file mode 100644
index 0000000..a20d041
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaRetrievalService.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.md.sal.rest.schema;
+
+import com.google.common.annotations.Beta;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import org.opendaylight.restconf.common.schema.SchemaExportContext;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+
+/**
+ * Retrieval of the YANG modules which server supports.
+ *
+ * @deprecated do not use this api. It is replaced by RestconfSchemaService
+ */
+@Deprecated
+@Beta
+public interface SchemaRetrievalService {
+ @GET
+ @Produces({YangConstants.RFC6020_YIN_MEDIA_TYPE, YangConstants.RFC6020_YANG_MEDIA_TYPE})
+ @Path("/modules/module/{identifier:.+}/schema")
+ SchemaExportContext getSchema(@PathParam("identifier") String mountAndModuleId);
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaRetrievalServiceImpl.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaRetrievalServiceImpl.java
new file mode 100644
index 0000000..ad23992
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/md/sal/rest/schema/SchemaRetrievalServiceImpl.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.md.sal.rest.schema;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+import java.time.format.DateTimeParseException;
+import java.util.Iterator;
+import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.schema.SchemaExportContext;
+import org.opendaylight.restconf.common.validation.RestconfValidationUtils;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class SchemaRetrievalServiceImpl implements SchemaRetrievalService {
+
+ private final ControllerContext salContext;
+
+ private static final Splitter SLASH_SPLITTER = Splitter.on("/");
+ private static final String MOUNT_ARG = ControllerContext.MOUNT;
+
+ public SchemaRetrievalServiceImpl(final ControllerContext controllerContext) {
+ salContext = controllerContext;
+ }
+
+
+ @Override
+ public SchemaExportContext getSchema(final String mountAndModule) {
+ final SchemaContext schemaContext;
+ final Iterable<String> pathComponents = SLASH_SPLITTER.split(mountAndModule);
+ final Iterator<String> componentIter = pathComponents.iterator();
+ if (!Iterables.contains(pathComponents, MOUNT_ARG)) {
+ schemaContext = salContext.getGlobalSchema();
+ } else {
+ final StringBuilder pathBuilder = new StringBuilder();
+ while (componentIter.hasNext()) {
+ final String current = componentIter.next();
+ // It is argument, not last element.
+ if (pathBuilder.length() != 0) {
+ pathBuilder.append("/");
+ }
+ pathBuilder.append(current);
+ if (MOUNT_ARG.equals(current)) {
+ // We stop right at mountpoint, last two arguments should
+ // be module name and revision
+ break;
+ }
+ }
+ schemaContext = getMountSchemaContext(pathBuilder.toString());
+
+ }
+
+ RestconfDocumentedException.throwIf(!componentIter.hasNext(), "Module name must be supplied.",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ final String moduleName = componentIter.next();
+ RestconfDocumentedException.throwIf(!componentIter.hasNext(), "Revision date must be supplied.",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ final String revisionString = componentIter.next();
+ return getExportUsingNameAndRevision(schemaContext, moduleName, revisionString,
+ salContext.getYangTextSourceProvider());
+ }
+
+ private static SchemaExportContext getExportUsingNameAndRevision(final SchemaContext schemaContext,
+ final String moduleName, final String revisionStr,
+ final DOMYangTextSourceProvider yangTextSourceProvider) {
+ try {
+ final Module module = schemaContext.findModule(moduleName, Revision.of(revisionStr)).orElse(null);
+ return new SchemaExportContext(
+ schemaContext, RestconfValidationUtils.checkNotNullDocumented(module, moduleName),
+ yangTextSourceProvider);
+ } catch (final DateTimeParseException e) {
+ throw new RestconfDocumentedException("Supplied revision is not in expected date format YYYY-mm-dd", e);
+ }
+ }
+
+ private SchemaContext getMountSchemaContext(final String identifier) {
+ final InstanceIdentifierContext mountContext = salContext.toMountPointIdentifier(identifier);
+ return mountContext.getSchemaContext();
+ }
+}
+
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/Draft02.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/Draft02.java
new file mode 100644
index 0000000..67c8729
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/Draft02.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.api;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+/**
+ * Base Draft for Restconf project.
+ *
+ * @deprecated Do not use old implementation of restconf draft. It will be replaced by Rfc8040.
+ */
+@Deprecated
+public class Draft02 {
+ public interface MediaTypes {
+ String API = "application/yang.api";
+ String DATASTORE = "application/yang.datastore";
+ String DATA = "application/yang.data";
+ String OPERATION = "application/yang.operation";
+ String PATCH = "application/yang.patch";
+ String PATCH_STATUS = "application/yang.patch-status";
+ String STREAM = "application/yang.stream";
+ }
+
+ public interface RestConfModule {
+ String REVISION = "2013-10-19";
+
+ String NAME = "ietf-restconf";
+
+ String NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-restconf";
+
+ String RESTCONF_GROUPING_SCHEMA_NODE = "restconf";
+
+ String RESTCONF_CONTAINER_SCHEMA_NODE = "restconf";
+
+ String MODULES_CONTAINER_SCHEMA_NODE = "modules";
+
+ String MODULE_LIST_SCHEMA_NODE = "module";
+
+ String STREAMS_CONTAINER_SCHEMA_NODE = "streams";
+
+ String STREAM_LIST_SCHEMA_NODE = "stream";
+
+ String ERROR_LIST_SCHEMA_NODE = "error";
+
+ QName IETF_RESTCONF_QNAME = QName.create(Draft02.RestConfModule.NAMESPACE, Draft02.RestConfModule.REVISION,
+ Draft02.RestConfModule.NAME);
+
+ QName ERRORS_QNAME = QName.create(IETF_RESTCONF_QNAME, "errors");
+
+ QName ERROR_LIST_QNAME = QName.create(IETF_RESTCONF_QNAME, ERROR_LIST_SCHEMA_NODE);
+
+ QName ERROR_TYPE_QNAME = QName.create(IETF_RESTCONF_QNAME, "error-type");
+
+ QName ERROR_TAG_QNAME = QName.create(IETF_RESTCONF_QNAME, "error-tag");
+
+ QName ERROR_APP_TAG_QNAME = QName.create(IETF_RESTCONF_QNAME, "error-app-tag");
+
+ QName ERROR_MESSAGE_QNAME = QName.create(IETF_RESTCONF_QNAME, "error-message");
+
+ QName ERROR_INFO_QNAME = QName.create(IETF_RESTCONF_QNAME, "error-info");
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestConnector.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestConnector.java
new file mode 100644
index 0000000..3200958
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestConnector.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.sal.rest.api;
+
+/*
+ * This is a simple dummy interface to allow us to create instances of RestconfProvider
+ * via the config subsystem.
+ */
+public interface RestConnector {
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfConstants.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfConstants.java
new file mode 100644
index 0000000..6a4ba93
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfConstants.java
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.sal.rest.api;
+
+public interface RestconfConstants {
+
+ String IDENTIFIER = "identifier";
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfNormalizedNodeWriter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfNormalizedNodeWriter.java
new file mode 100644
index 0000000..eb160bd
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfNormalizedNodeWriter.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.api;
+
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface RestconfNormalizedNodeWriter extends Flushable, Closeable {
+
+ RestconfNormalizedNodeWriter write(NormalizedNode node) throws IOException;
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfService.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfService.java
new file mode 100644
index 0000000..0d0d2ab
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/RestconfService.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.api;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.netconf.sal.rest.api.Draft02.MediaTypes;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.restconf.common.patch.Patch;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+
+/**
+ * The URI hierarchy for the RESTCONF resources consists of an entry point
+ * container, 4 top-level resources, and 1 field.
+ * <ul>
+ * <li><b>/restconf</b> - {@link #getRoot()}
+ * <ul>
+ * <li><b>/config</b> - {@link #readConfigurationData(String, UriInfo)}
+ * {@link #updateConfigurationData(String, NormalizedNodeContext, UriInfo)}
+ * {@link #createConfigurationData(NormalizedNodeContext, UriInfo)}
+ * {@link #createConfigurationData(String, NormalizedNodeContext, UriInfo)}
+ * {@link #deleteConfigurationData(String)}
+ * <li><b>/operational</b> - {@link #readOperationalData(String, UriInfo)}
+ * <li>/modules - {@link #getModules(UriInfo)}
+ * <ul>
+ * <li>/module
+ * </ul>
+ * <li><b>/operations</b> -
+ * {@link #invokeRpc(String, NormalizedNodeContext, UriInfo)}
+ * {@link #invokeRpc(String, NormalizedNodeContext, UriInfo)}
+ * <li>/version (field)
+ * </ul>
+ * </ul>
+ */
+@Path("/")
+public interface RestconfService {
+
+ String XML = "+xml";
+ String JSON = "+json";
+
+ @GET
+ Object getRoot();
+
+ /**
+ * Get all modules supported by controller.
+ *
+ * @param uriInfo
+ * URI info
+ * @return {@link NormalizedNodeContext}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#readData(UriInfo)
+ */
+ @Deprecated
+ @GET
+ @Path("/modules")
+ @Produces({
+ Draft02.MediaTypes.API + JSON,
+ Draft02.MediaTypes.API + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ NormalizedNodeContext getModules(@Context UriInfo uriInfo);
+
+ /**
+ * Get all modules supported by mount point.
+ *
+ * @param identifier
+ * mount point identifier
+ * @param uriInfo
+ * URI info
+ * @return {@link NormalizedNodeContext}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#readData(String,
+ * UriInfo)
+ */
+ @Deprecated
+ @GET
+ @Path("/modules/{identifier:.+}")
+ @Produces({
+ Draft02.MediaTypes.API + JSON,
+ Draft02.MediaTypes.API + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ NormalizedNodeContext getModules(@PathParam("identifier") String identifier, @Context UriInfo uriInfo);
+
+ /**
+ * Get module.
+ *
+ * @param identifier
+ * path to target
+ * @param uriInfo
+ * URI info
+ * @return {@link NormalizedNodeContext}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#readData(String,
+ * UriInfo)
+ */
+ @Deprecated
+ @GET
+ @Path("/modules/module/{identifier:.+}")
+ @Produces({
+ Draft02.MediaTypes.API + JSON,
+ Draft02.MediaTypes.API + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ NormalizedNodeContext getModule(@PathParam("identifier") String identifier, @Context UriInfo uriInfo);
+
+ /**
+ * List of rpc or action operations supported by the server.
+ *
+ * @return A JSON document string
+ * @deprecated do not use this method. It will be replaced by
+ * RestconfOperationsService#getOperations(UriInfo)
+ */
+ @Deprecated
+ @GET
+ @Path("/operations")
+ @Produces({ Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON })
+ String getOperationsJSON();
+
+ /**
+ * List of rpc or action operations supported by the server.
+ *
+ * @return A XML document string
+ * @deprecated do not use this method. It will be replaced by
+ * RestconfOperationsService#getOperations(UriInfo)
+ */
+ @Deprecated
+ @GET
+ @Path("/operations")
+ @Produces({ Draft02.MediaTypes.API + XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ String getOperationsXML();
+
+ /**
+ * Valid for mount points. List of operations supported by the server.
+ *
+ * @param identifier
+ * path parameter
+ * @param uriInfo
+ * URI information
+ * @return {@link NormalizedNodeContext}
+ * @deprecated do not use this method. It will be replaced by
+ * RestconfOperationsService#getOperations(String, UriInfo)
+ */
+ @Deprecated
+ @GET
+ @Path("/operations/{identifier:.+}")
+ @Produces({
+ Draft02.MediaTypes.API + JSON,
+ Draft02.MediaTypes.API + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ NormalizedNodeContext getOperations(@PathParam("identifier") String identifier, @Context UriInfo uriInfo);
+
+ /**
+ * Invoke RPC operation.
+ *
+ * @param identifier
+ * module name and rpc identifier string for the desired operation
+ * @param payload
+ * {@link NormalizedNodeContext} - the body of the operation
+ * @param uriInfo
+ * URI info
+ * @return {@link NormalizedNodeContext}
+ * @deprecated do not use this method. It will be replaced by
+ * RestconfInvokeOperationsService#invokeRpc(String, NormalizedNodeContext, UriInfo)
+ */
+ @Deprecated
+ @POST
+ @Path("/operations/{identifier:.+}")
+ @Produces({
+ Draft02.MediaTypes.OPERATION + JSON,
+ Draft02.MediaTypes.OPERATION + XML,
+ Draft02.MediaTypes.DATA + JSON,
+ Draft02.MediaTypes.DATA + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ @Consumes({
+ Draft02.MediaTypes.OPERATION + JSON,
+ Draft02.MediaTypes.OPERATION + XML,
+ Draft02.MediaTypes.DATA + JSON,
+ Draft02.MediaTypes.DATA + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ NormalizedNodeContext invokeRpc(@Encoded @PathParam("identifier") String identifier, NormalizedNodeContext payload,
+ @Context UriInfo uriInfo);
+
+ /**
+ * Get target data resource from config data store.
+ *
+ * @param identifier
+ * path to target
+ * @param uriInfo
+ * URI info
+ * @return {@link NormalizedNodeContext}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#readData(String,
+ * UriInfo)
+ */
+ @Deprecated
+ @GET
+ @Path("/config/{identifier:.+}")
+ @Produces({
+ Draft02.MediaTypes.DATA + JSON,
+ Draft02.MediaTypes.DATA + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ NormalizedNodeContext readConfigurationData(@Encoded @PathParam("identifier") String identifier,
+ @Context UriInfo uriInfo);
+
+ /**
+ * Get target data resource from operational data store.
+ *
+ * @param identifier
+ * path to target
+ * @param uriInfo
+ * URI info
+ * @return {@link NormalizedNodeContext}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#readData(String,
+ * UriInfo)
+ */
+ @Deprecated
+ @GET
+ @Path("/operational/{identifier:.+}")
+ @Produces({
+ Draft02.MediaTypes.DATA + JSON,
+ Draft02.MediaTypes.DATA + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ NormalizedNodeContext readOperationalData(@Encoded @PathParam("identifier") String identifier,
+ @Context UriInfo uriInfo);
+
+ /**
+ * Create or replace the target data resource.
+ *
+ * @param identifier
+ * path to target
+ * @param payload
+ * data node for put to config DS
+ * @return {@link Response}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#putData(String,
+ * NormalizedNodeContext, UriInfo)
+ */
+ @Deprecated
+ @PUT
+ @Path("/config/{identifier:.+}")
+ @Consumes({
+ Draft02.MediaTypes.DATA + JSON,
+ Draft02.MediaTypes.DATA + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ Response updateConfigurationData(@Encoded @PathParam("identifier") String identifier,
+ NormalizedNodeContext payload, @Context UriInfo uriInfo);
+
+ /**
+ * Create a data resource in target.
+ *
+ * @param identifier
+ * path to target
+ * @param payload
+ * new data
+ * @param uriInfo
+ * URI info
+ * @return {@link Response}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#postData(String,
+ * NormalizedNodeContext, UriInfo)
+ */
+ @Deprecated
+ @POST
+ @Path("/config/{identifier:.+}")
+ @Consumes({
+ Draft02.MediaTypes.DATA + JSON,
+ Draft02.MediaTypes.DATA + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ Response createConfigurationData(@Encoded @PathParam("identifier") String identifier, NormalizedNodeContext payload,
+ @Context UriInfo uriInfo);
+
+ /**
+ * Create a data resource.
+ *
+ * @param payload
+ * new data
+ * @param uriInfo
+ * URI info
+ * @return {@link Response}
+ * @deprecated do not use this method. It will be replaced by
+ * RestconfDataService#postData(NormalizedNodeContext, UriInfo)
+ */
+ @Deprecated
+ @POST
+ @Path("/config")
+ @Consumes({
+ Draft02.MediaTypes.DATA + JSON,
+ Draft02.MediaTypes.DATA + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ Response createConfigurationData(NormalizedNodeContext payload, @Context UriInfo uriInfo);
+
+ /**
+ * Delete the target data resource.
+ *
+ * @param identifier
+ * path to target
+ * @return {@link Response}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#deleteData(String)
+ */
+ @Deprecated
+ @DELETE
+ @Path("/config/{identifier:.+}")
+ Response deleteConfigurationData(@Encoded @PathParam("identifier") String identifier);
+
+ /**
+ * Subscribe to stream.
+ *
+ * @param identifier
+ * stream identifier
+ * @param uriInfo
+ * URI info
+ * @return {@link NormalizedNodeContext}
+ * @deprecated do not use this method. It will be replaced by
+ * RestconfStreamsSubscriptionService#subscribeToStream(String, UriInfo)
+ */
+ @Deprecated
+ @GET
+ @Path("/streams/stream/{identifier:.+}")
+ NormalizedNodeContext subscribeToStream(@Encoded @PathParam("identifier") String identifier,
+ @Context UriInfo uriInfo);
+
+ /**
+ * Get list of all streams.
+ *
+ * @param uriInfo
+ * URI info
+ * @return {@link NormalizedNodeContext}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#readData(String,
+ * UriInfo)
+ **/
+ @Deprecated
+ @GET
+ @Path("/streams")
+ @Produces({
+ Draft02.MediaTypes.API + JSON,
+ Draft02.MediaTypes.API + XML,
+ MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+ })
+ NormalizedNodeContext getAvailableStreams(@Context UriInfo uriInfo);
+
+ /**
+ * Ordered list of edits that are applied to the target datastore by the server.
+ *
+ * @param identifier
+ * path to target
+ * @param context
+ * edits
+ * @param uriInfo
+ * URI info
+ * @return {@link PatchStatusContext}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#patchData(String,
+ * PatchContext, UriInfo)
+ */
+ @Deprecated
+ @Patch
+ @Path("/config/{identifier:.+}")
+ @Consumes({
+ MediaTypes.PATCH + JSON,
+ MediaTypes.PATCH + XML
+ })
+ @Produces({
+ MediaTypes.PATCH_STATUS + JSON,
+ MediaTypes.PATCH_STATUS + XML
+ })
+ PatchStatusContext patchConfigurationData(@Encoded @PathParam("identifier") String identifier, PatchContext
+ context, @Context UriInfo uriInfo);
+
+ /**
+ * Ordered list of edits that are applied to the datastore by the server.
+ *
+ * @param context
+ * edits
+ * @param uriInfo
+ * URI info
+ * @return {@link PatchStatusContext}
+ * @deprecated do not use this method. It will be replaced by RestconfDataService#patchData(PatchContext,
+ * UriInfo)
+ */
+ @Deprecated
+ @Patch
+ @Path("/config")
+ @Consumes({
+ MediaTypes.PATCH + JSON,
+ MediaTypes.PATCH + XML
+ })
+ @Produces({
+ MediaTypes.PATCH_STATUS + JSON,
+ MediaTypes.PATCH_STATUS + XML
+ })
+ PatchStatusContext patchConfigurationData(PatchContext context, @Context UriInfo uriInfo);
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/package-info.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/package-info.java
new file mode 100644
index 0000000..b765331
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/api/package-info.java
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.api;
+
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/AbstractIdentifierAwareJaxRsProvider.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/AbstractIdentifierAwareJaxRsProvider.java
new file mode 100644
index 0000000..76ffdb4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/AbstractIdentifierAwareJaxRsProvider.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.sal.rest.impl;
+
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.netconf.sal.rest.api.RestconfConstants;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+
+/**
+ * JAX-RS Provider.
+ *
+ * @deprecated This class will be replaced by AbstractIdentifierAwareJaxRsProvider in restconf-nb-rfc8040
+ */
+@Deprecated
+public class AbstractIdentifierAwareJaxRsProvider {
+
+ private static final String POST = "POST";
+
+ @Context
+ private UriInfo uriInfo;
+
+ @Context
+ private Request request;
+
+ private final ControllerContext controllerContext;
+
+ protected AbstractIdentifierAwareJaxRsProvider(final ControllerContext controllerContext) {
+ this.controllerContext = controllerContext;
+ }
+
+ protected final String getIdentifier() {
+ return uriInfo.getPathParameters(false).getFirst(RestconfConstants.IDENTIFIER);
+ }
+
+ protected InstanceIdentifierContext getInstanceIdentifierContext() {
+ return controllerContext.toInstanceIdentifier(getIdentifier());
+ }
+
+ protected UriInfo getUriInfo() {
+ return uriInfo;
+ }
+
+ protected boolean isPost() {
+ return POST.equals(request.getMethod());
+ }
+
+ protected ControllerContext getControllerContext() {
+ return controllerContext;
+ }
+
+ Request getRequest() {
+ return request;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriter.java
new file mode 100644
index 0000000..b9d7a7a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriter.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import static java.util.Objects.requireNonNull;
+import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
+
+import com.google.common.collect.Iterables;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.netconf.sal.rest.api.RestconfNormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyxmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UserLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UserMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is an experimental iterator over a {@link NormalizedNode}. This is essentially the opposite of a
+ * {@link javax.xml.stream.XMLStreamReader} -- unlike instantiating an iterator over the backing data, this
+ * encapsulates a {@link NormalizedNodeStreamWriter} and allows us to write multiple nodes.
+ *
+ * @deprecated This class will be replaced by ParameterAwareNormalizedNodeWriter in restconf-nb-rfc8040
+ */
+@Deprecated
+public class DepthAwareNormalizedNodeWriter implements RestconfNormalizedNodeWriter {
+ private final NormalizedNodeStreamWriter writer;
+ protected int currentDepth = 0;
+ protected final int maxDepth;
+
+ private DepthAwareNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final int maxDepth) {
+ this.writer = requireNonNull(writer);
+ this.maxDepth = maxDepth;
+ }
+
+ protected final NormalizedNodeStreamWriter getWriter() {
+ return writer;
+ }
+
+ /**
+ * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
+ *
+ * @param writer Back-end writer
+ * @return A new instance.
+ */
+ public static DepthAwareNormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
+ final int maxDepth) {
+ return forStreamWriter(writer, true, maxDepth);
+ }
+
+ /**
+ * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
+ * Unlike the simple {@link #forStreamWriter(NormalizedNodeStreamWriter, int)}
+ * method, this allows the caller to switch off RFC6020 XML compliance, providing better
+ * throughput. The reason is that the XML mapping rules in RFC6020 require the encoding
+ * to emit leaf nodes which participate in a list's key first and in the order in which
+ * they are defined in the key. For JSON, this requirement is completely relaxed and leaves
+ * can be ordered in any way we see fit. The former requires a bit of work: first a lookup
+ * for each key and then for each emitted node we need to check whether it was already
+ * emitted.
+ *
+ * @param writer Back-end writer
+ * @param orderKeyLeaves whether the returned instance should be RFC6020 XML compliant.
+ * @return A new instance.
+ */
+ public static DepthAwareNormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
+ final boolean orderKeyLeaves, final int maxDepth) {
+ return orderKeyLeaves ? new OrderedDepthAwareNormalizedNodeWriter(writer, maxDepth)
+ : new DepthAwareNormalizedNodeWriter(writer, maxDepth);
+ }
+
+ /**
+ * Iterate over the provided {@link NormalizedNode} and emit write
+ * events to the encapsulated {@link NormalizedNodeStreamWriter}.
+ *
+ * @param node Node
+ * @return DepthAwareNormalizedNodeWriter
+ * @throws IOException when thrown from the backing writer.
+ */
+ @Override
+ public final DepthAwareNormalizedNodeWriter write(final NormalizedNode node) throws IOException {
+ if (wasProcessedAsCompositeNode(node)) {
+ return this;
+ }
+
+ if (wasProcessAsSimpleNode(node)) {
+ return this;
+ }
+
+ throw new IllegalStateException("It wasn't possible to serialize node " + node);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ writer.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ writer.flush();
+ writer.close();
+ }
+
+ /**
+ * Emit a best guess of a hint for a particular set of children. It evaluates the
+ * iterable to see if the size can be easily gotten to. If it is, we hint at the
+ * real number of child nodes. Otherwise we emit UNKNOWN_SIZE.
+ *
+ * @param children Child nodes
+ * @return Best estimate of the collection size required to hold all the children.
+ */
+ static final int childSizeHint(final Iterable<?> children) {
+ return children instanceof Collection ? ((Collection<?>) children).size() : UNKNOWN_SIZE;
+ }
+
+ private boolean wasProcessAsSimpleNode(final NormalizedNode node) throws IOException {
+ if (node instanceof LeafSetEntryNode) {
+ if (currentDepth < maxDepth) {
+ final LeafSetEntryNode<?> nodeAsLeafList = (LeafSetEntryNode<?>) node;
+ writer.startLeafSetEntryNode(nodeAsLeafList.getIdentifier());
+ writer.scalarValue(nodeAsLeafList.body());
+ writer.endNode();
+ }
+ return true;
+ } else if (node instanceof LeafNode) {
+ final LeafNode<?> nodeAsLeaf = (LeafNode<?>)node;
+ writer.startLeafNode(nodeAsLeaf.getIdentifier());
+ writer.scalarValue(nodeAsLeaf.body());
+ writer.endNode();
+ return true;
+ } else if (node instanceof AnyxmlNode) {
+ final AnyxmlNode<?> anyxmlNode = (AnyxmlNode<?>)node;
+ final Class<?> objectModel = anyxmlNode.bodyObjectModel();
+ if (writer.startAnyxmlNode(anyxmlNode.getIdentifier(), objectModel)) {
+ if (DOMSource.class.isAssignableFrom(objectModel)) {
+ writer.domSourceValue((DOMSource) anyxmlNode.body());
+ } else {
+ writer.scalarValue(anyxmlNode.body());
+ }
+ writer.endNode();
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Emit events for all children and then emit an endNode() event.
+ *
+ * @param children Child iterable
+ * @return True
+ * @throws IOException when the writer reports it
+ */
+ protected final boolean writeChildren(final Iterable<? extends NormalizedNode> children) throws IOException {
+ if (currentDepth < maxDepth) {
+ for (final NormalizedNode child : children) {
+ write(child);
+ }
+ }
+ writer.endNode();
+ return true;
+ }
+
+ protected boolean writeMapEntryChildren(final MapEntryNode mapEntryNode) throws IOException {
+ if (currentDepth < maxDepth) {
+ writeChildren(mapEntryNode.body());
+ } else if (currentDepth == maxDepth) {
+ writeOnlyKeys(mapEntryNode.getIdentifier().entrySet());
+ }
+ return true;
+ }
+
+ private void writeOnlyKeys(final Set<Entry<QName, Object>> entries) throws IOException {
+ for (final Entry<QName, Object> entry : entries) {
+ writer.startLeafNode(new NodeIdentifier(entry.getKey()));
+ writer.scalarValue(entry.getValue());
+ writer.endNode();
+ }
+ writer.endNode();
+ }
+
+ protected boolean writeMapEntryNode(final MapEntryNode node) throws IOException {
+ writer.startMapEntryNode(node.getIdentifier(), childSizeHint(node.body()));
+ currentDepth++;
+ writeMapEntryChildren(node);
+ currentDepth--;
+ return true;
+ }
+
+ private boolean wasProcessedAsCompositeNode(final NormalizedNode node) throws IOException {
+ boolean processedAsCompositeNode = false;
+ if (node instanceof ContainerNode) {
+ final ContainerNode n = (ContainerNode) node;
+ writer.startContainerNode(n.getIdentifier(), childSizeHint(n.body()));
+ currentDepth++;
+ processedAsCompositeNode = writeChildren(n.body());
+ currentDepth--;
+ } else if (node instanceof MapEntryNode) {
+ processedAsCompositeNode = writeMapEntryNode((MapEntryNode) node);
+ } else if (node instanceof UnkeyedListEntryNode) {
+ final UnkeyedListEntryNode n = (UnkeyedListEntryNode) node;
+ writer.startUnkeyedListItem(n.getIdentifier(), childSizeHint(n.body()));
+ currentDepth++;
+ processedAsCompositeNode = writeChildren(n.body());
+ currentDepth--;
+ } else if (node instanceof ChoiceNode) {
+ final ChoiceNode n = (ChoiceNode) node;
+ writer.startChoiceNode(n.getIdentifier(), childSizeHint(n.body()));
+ processedAsCompositeNode = writeChildren(n.body());
+ } else if (node instanceof AugmentationNode) {
+ final AugmentationNode n = (AugmentationNode) node;
+ writer.startAugmentationNode(n.getIdentifier());
+ processedAsCompositeNode = writeChildren(n.body());
+ } else if (node instanceof UnkeyedListNode) {
+ final UnkeyedListNode n = (UnkeyedListNode) node;
+ writer.startUnkeyedList(n.getIdentifier(), childSizeHint(n.body()));
+ processedAsCompositeNode = writeChildren(n.body());
+ } else if (node instanceof UserMapNode) {
+ final UserMapNode n = (UserMapNode) node;
+ writer.startOrderedMapNode(n.getIdentifier(), childSizeHint(n.body()));
+ processedAsCompositeNode = writeChildren(n.body());
+ } else if (node instanceof MapNode) {
+ final MapNode n = (MapNode) node;
+ writer.startMapNode(n.getIdentifier(), childSizeHint(n.body()));
+ processedAsCompositeNode = writeChildren(n.body());
+ } else if (node instanceof LeafSetNode) {
+ final LeafSetNode<?> n = (LeafSetNode<?>) node;
+ if (node instanceof UserLeafSetNode) {
+ writer.startOrderedLeafSet(n.getIdentifier(), childSizeHint(n.body()));
+ } else {
+ writer.startLeafSet(n.getIdentifier(), childSizeHint(n.body()));
+ }
+ currentDepth++;
+ processedAsCompositeNode = writeChildren(n.body());
+ currentDepth--;
+ }
+
+ return processedAsCompositeNode;
+ }
+
+ private static final class OrderedDepthAwareNormalizedNodeWriter extends DepthAwareNormalizedNodeWriter {
+ private static final Logger LOG = LoggerFactory.getLogger(OrderedDepthAwareNormalizedNodeWriter.class);
+
+ OrderedDepthAwareNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final int maxDepth) {
+ super(writer, maxDepth);
+ }
+
+ @Override
+ protected boolean writeMapEntryNode(final MapEntryNode node) throws IOException {
+ final NormalizedNodeStreamWriter writer = getWriter();
+ writer.startMapEntryNode(node.getIdentifier(), childSizeHint(node.body()));
+
+ final Set<QName> qnames = node.getIdentifier().keySet();
+ // Write out all the key children
+ for (final QName qname : qnames) {
+ final Optional<? extends NormalizedNode> child = node.findChildByArg(new NodeIdentifier(qname));
+ if (child.isPresent()) {
+ write(child.get());
+ } else {
+ LOG.info("No child for key element {} found", qname);
+ }
+ }
+
+ // Write all the rest
+ currentDepth++;
+ final boolean result = writeChildren(Iterables.filter(node.body(), input -> {
+ if (input instanceof AugmentationNode) {
+ return true;
+ }
+ if (!qnames.contains(input.getIdentifier().getNodeType())) {
+ return true;
+ }
+
+ LOG.debug("Skipping key child {}", input);
+ return false;
+ }));
+ currentDepth--;
+ return result;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/JsonNormalizedNodeBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/JsonNormalizedNodeBodyReader.java
new file mode 100644
index 0000000..aecea7a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/JsonNormalizedNodeBodyReader.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+import com.google.gson.stream.JsonReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.util.RestUtil;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.data.impl.schema.ResultAlreadySetException;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Provider
+@Consumes({
+ Draft02.MediaTypes.DATA + RestconfService.JSON,
+ Draft02.MediaTypes.OPERATION + RestconfService.JSON,
+ MediaType.APPLICATION_JSON
+})
+public class JsonNormalizedNodeBodyReader
+ extends AbstractIdentifierAwareJaxRsProvider implements MessageBodyReader<NormalizedNodeContext> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JsonNormalizedNodeBodyReader.class);
+
+ public JsonNormalizedNodeBodyReader(final ControllerContext controllerContext) {
+ super(controllerContext);
+ }
+
+ @Override
+ public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+ final MediaType mediaType) {
+ return true;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public NormalizedNodeContext readFrom(final Class<NormalizedNodeContext> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream) throws
+ WebApplicationException {
+ try {
+ return readFrom(getInstanceIdentifierContext(), entityStream, isPost());
+ } catch (final Exception e) {
+ propagateExceptionAs(e);
+ return null; // no-op
+ }
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public static NormalizedNodeContext readFrom(final String uriPath, final InputStream entityStream,
+ final boolean isPost, final ControllerContext controllerContext) throws RestconfDocumentedException {
+
+ try {
+ return readFrom(controllerContext.toInstanceIdentifier(uriPath), entityStream, isPost);
+ } catch (final Exception e) {
+ propagateExceptionAs(e);
+ return null; // no-op
+ }
+ }
+
+ private static NormalizedNodeContext readFrom(final InstanceIdentifierContext path,
+ final InputStream entityStream, final boolean isPost)
+ throws IOException {
+ final Optional<InputStream> nonEmptyInputStreamOptional = RestUtil.isInputStreamEmpty(entityStream);
+ if (nonEmptyInputStreamOptional.isEmpty()) {
+ return new NormalizedNodeContext(path, null);
+ }
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+
+ final Inference parentInference;
+ if (isPost && !(path.getSchemaNode() instanceof RpcDefinition)) {
+ parentInference = path.inference();
+ } else {
+ final var inference = path.inference();
+ if (!inference.statementPath().isEmpty()) {
+ final var stack = inference.toSchemaInferenceStack();
+ stack.exit();
+ parentInference = stack.toInference();
+ } else {
+ parentInference = inference;
+ }
+ }
+
+ final JsonParserStream jsonParser = JsonParserStream.create(writer,
+ JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(path.getSchemaContext()),
+ parentInference);
+ final JsonReader reader = new JsonReader(new InputStreamReader(nonEmptyInputStreamOptional.get(),
+ StandardCharsets.UTF_8));
+ jsonParser.parse(reader);
+
+ NormalizedNode result = resultHolder.getResult();
+ final List<YangInstanceIdentifier.PathArgument> iiToDataList = new ArrayList<>();
+ InstanceIdentifierContext newIIContext;
+
+ while (result instanceof AugmentationNode || result instanceof ChoiceNode) {
+ final Object childNode = ((DataContainerNode) result).body().iterator().next();
+ if (isPost) {
+ iiToDataList.add(result.getIdentifier());
+ }
+ result = (NormalizedNode) childNode;
+ }
+
+ if (isPost) {
+ if (result instanceof MapEntryNode) {
+ iiToDataList.add(new YangInstanceIdentifier.NodeIdentifier(result.getIdentifier().getNodeType()));
+ iiToDataList.add(result.getIdentifier());
+ } else {
+ iiToDataList.add(result.getIdentifier());
+ }
+ } else {
+ if (result instanceof MapNode) {
+ result = Iterables.getOnlyElement(((MapNode) result).body());
+ }
+ }
+
+ return new NormalizedNodeContext(path.withConcatenatedArgs(iiToDataList), result);
+ }
+
+ private static void propagateExceptionAs(final Exception exception) throws RestconfDocumentedException {
+ Throwables.throwIfInstanceOf(exception, RestconfDocumentedException.class);
+ LOG.debug("Error parsing json input", exception);
+
+ if (exception instanceof ResultAlreadySetException) {
+ throw new RestconfDocumentedException("Error parsing json input: Failed to create new parse result data. "
+ + "Are you creating multiple resources/subresources in POST request?", exception);
+ }
+
+ RestconfDocumentedException.throwIfYangError(exception);
+ throw new RestconfDocumentedException("Error parsing input: " + exception.getMessage(), ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE, exception);
+ }
+}
+
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/JsonToPatchBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/JsonToPatchBodyReader.java
new file mode 100644
index 0000000..ce5a8c4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/JsonToPatchBodyReader.java
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import static com.google.common.base.Verify.verify;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchEditOperation;
+import org.opendaylight.restconf.common.patch.PatchEntity;
+import org.opendaylight.restconf.common.util.RestUtil;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.data.impl.schema.ResultAlreadySetException;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Patch reader for JSON.
+ *
+ * @deprecated This class will be replaced by JsonToPatchBodyReader in restconf-nb-rfc8040
+ */
+@Deprecated
+@Provider
+@Consumes({Draft02.MediaTypes.PATCH + RestconfService.JSON})
+public class JsonToPatchBodyReader extends AbstractIdentifierAwareJaxRsProvider
+ implements MessageBodyReader<PatchContext> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JsonToPatchBodyReader.class);
+
+ public JsonToPatchBodyReader(final ControllerContext controllerContext) {
+ super(controllerContext);
+ }
+
+ @Override
+ public boolean isReadable(final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
+ return true;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public PatchContext readFrom(final Class<PatchContext> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream)
+ throws WebApplicationException {
+ try {
+ return readFrom(getInstanceIdentifierContext(), entityStream);
+ } catch (final Exception e) {
+ throw propagateExceptionAs(e);
+ }
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public PatchContext readFrom(final String uriPath, final InputStream entityStream) throws
+ RestconfDocumentedException {
+ try {
+ return readFrom(getControllerContext().toInstanceIdentifier(uriPath), entityStream);
+ } catch (final Exception e) {
+ propagateExceptionAs(e);
+ return null; // no-op
+ }
+ }
+
+ private PatchContext readFrom(final InstanceIdentifierContext path, final InputStream entityStream)
+ throws IOException {
+ final Optional<InputStream> nonEmptyInputStreamOptional = RestUtil.isInputStreamEmpty(entityStream);
+ if (nonEmptyInputStreamOptional.isEmpty()) {
+ return new PatchContext(path, null, null);
+ }
+
+ final JsonReader jsonReader = new JsonReader(new InputStreamReader(nonEmptyInputStreamOptional.get(),
+ StandardCharsets.UTF_8));
+ AtomicReference<String> patchId = new AtomicReference<>();
+ final List<PatchEntity> resultList = read(jsonReader, path, patchId);
+ jsonReader.close();
+
+ return new PatchContext(path, resultList, patchId.get());
+ }
+
+ private static RuntimeException propagateExceptionAs(final Exception exception) throws RestconfDocumentedException {
+ Throwables.throwIfInstanceOf(exception, RestconfDocumentedException.class);
+ LOG.debug("Error parsing json input", exception);
+
+ if (exception instanceof ResultAlreadySetException) {
+ throw new RestconfDocumentedException("Error parsing json input: Failed to create new parse result data. ");
+ }
+
+ RestconfDocumentedException.throwIfYangError(exception);
+ throw new RestconfDocumentedException("Error parsing json input: " + exception.getMessage(), ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE, exception);
+ }
+
+ private List<PatchEntity> read(final JsonReader in, final InstanceIdentifierContext path,
+ final AtomicReference<String> patchId) throws IOException {
+ final List<PatchEntity> resultCollection = new ArrayList<>();
+ final StringModuleInstanceIdentifierCodec codec = new StringModuleInstanceIdentifierCodec(
+ path.getSchemaContext());
+ final JsonToPatchBodyReader.PatchEdit edit = new JsonToPatchBodyReader.PatchEdit();
+
+ while (in.hasNext()) {
+ switch (in.peek()) {
+ case STRING:
+ case NUMBER:
+ in.nextString();
+ break;
+ case BOOLEAN:
+ Boolean.toString(in.nextBoolean());
+ break;
+ case NULL:
+ in.nextNull();
+ break;
+ case BEGIN_ARRAY:
+ in.beginArray();
+ break;
+ case BEGIN_OBJECT:
+ in.beginObject();
+ break;
+ case END_DOCUMENT:
+ break;
+ case NAME:
+ parseByName(in.nextName(), edit, in, path, codec, resultCollection, patchId);
+ break;
+ case END_OBJECT:
+ in.endObject();
+ break;
+ case END_ARRAY:
+ in.endArray();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return ImmutableList.copyOf(resultCollection);
+ }
+
+ /**
+ * Switch value of parsed JsonToken.NAME and read edit definition or patch id.
+ *
+ * @param name value of token
+ * @param edit PatchEdit instance
+ * @param in JsonReader reader
+ * @param path InstanceIdentifierContext context
+ * @param codec StringModuleInstanceIdentifierCodec codec
+ * @param resultCollection collection of parsed edits
+ * @throws IOException if operation fails
+ */
+ private void parseByName(final @NonNull String name, final @NonNull PatchEdit edit,
+ final @NonNull JsonReader in, final @NonNull InstanceIdentifierContext path,
+ final @NonNull StringModuleInstanceIdentifierCodec codec,
+ final @NonNull List<PatchEntity> resultCollection,
+ final @NonNull AtomicReference<String> patchId) throws IOException {
+ switch (name) {
+ case "edit" :
+ if (in.peek() == JsonToken.BEGIN_ARRAY) {
+ in.beginArray();
+
+ while (in.hasNext()) {
+ readEditDefinition(edit, in, path, codec);
+ resultCollection.add(prepareEditOperation(edit));
+ edit.clear();
+ }
+
+ in.endArray();
+ } else {
+ readEditDefinition(edit, in, path, codec);
+ resultCollection.add(prepareEditOperation(edit));
+ edit.clear();
+ }
+
+ break;
+ case "patch-id" :
+ patchId.set(in.nextString());
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Read one patch edit object from Json input.
+ * @param edit PatchEdit instance to be filled with read data
+ * @param in JsonReader reader
+ * @param path InstanceIdentifierContext path context
+ * @param codec StringModuleInstanceIdentifierCodec codec
+ * @throws IOException if operation fails
+ */
+ private void readEditDefinition(final @NonNull PatchEdit edit, final @NonNull JsonReader in,
+ final @NonNull InstanceIdentifierContext path,
+ final @NonNull StringModuleInstanceIdentifierCodec codec) throws IOException {
+ final StringBuilder value = new StringBuilder();
+ in.beginObject();
+
+ while (in.hasNext()) {
+ final String editDefinition = in.nextName();
+ switch (editDefinition) {
+ case "edit-id" :
+ edit.setId(in.nextString());
+ break;
+ case "operation" :
+ edit.setOperation(PatchEditOperation.valueOf(in.nextString().toUpperCase(Locale.ROOT)));
+ break;
+ case "target" :
+ // target can be specified completely in request URI
+ final String target = in.nextString();
+ if (target.equals("/")) {
+ edit.setTarget(path.getInstanceIdentifier());
+ edit.setTargetSchemaNode(SchemaInferenceStack.of(path.getSchemaContext()).toInference());
+ } else {
+ edit.setTarget(codec.deserialize(codec.serialize(path.getInstanceIdentifier()).concat(target)));
+
+ final var stack = codec.getDataContextTree().enterPath(edit.getTarget()).orElseThrow().stack();
+ stack.exit();
+ final EffectiveStatement<?, ?> parentStmt = stack.currentStatement();
+ verify(parentStmt instanceof SchemaNode, "Unexpected parent %s", parentStmt);
+ edit.setTargetSchemaNode(stack.toInference());
+ }
+
+ break;
+ case "value" :
+ // save data defined in value node for next (later) processing, because target needs to be read
+ // always first and there is no ordering in Json input
+ readValueNode(value, in);
+ break;
+ default:
+ break;
+ }
+ }
+
+ in.endObject();
+
+ // read saved data to normalized node when target schema is already known
+ edit.setData(readEditData(new JsonReader(
+ new StringReader(value.toString())), edit.getTargetSchemaNode(), path));
+ }
+
+ /**
+ * Parse data defined in value node and saves it to buffer.
+ * @param value Buffer to read value node
+ * @param in JsonReader reader
+ * @throws IOException if operation fails
+ */
+ private void readValueNode(final @NonNull StringBuilder value, final @NonNull JsonReader in) throws IOException {
+ in.beginObject();
+ value.append('{');
+
+ value.append('"').append(in.nextName()).append("\":");
+
+ if (in.peek() == JsonToken.BEGIN_ARRAY) {
+ in.beginArray();
+ value.append('[');
+
+ while (in.hasNext()) {
+ if (in.peek() == JsonToken.STRING) {
+ value.append('"').append(in.nextString()).append('"');
+ } else {
+ readValueObject(value, in);
+ }
+ if (in.peek() != JsonToken.END_ARRAY) {
+ value.append(',');
+ }
+ }
+
+ in.endArray();
+ value.append(']');
+ } else {
+ readValueObject(value, in);
+ }
+
+ in.endObject();
+ value.append('}');
+ }
+
+ /**
+ * Parse one value object of data and saves it to buffer.
+ * @param value Buffer to read value object
+ * @param in JsonReader reader
+ * @throws IOException if operation fails
+ */
+ private void readValueObject(final @NonNull StringBuilder value, final @NonNull JsonReader in) throws IOException {
+ // read simple leaf value
+ if (in.peek() == JsonToken.STRING) {
+ value.append('"').append(in.nextString()).append('"');
+ return;
+ }
+
+ in.beginObject();
+ value.append('{');
+
+ while (in.hasNext()) {
+ value.append('"').append(in.nextName()).append("\":");
+
+ if (in.peek() == JsonToken.STRING) {
+ value.append('"').append(in.nextString()).append('"');
+ } else {
+ if (in.peek() == JsonToken.BEGIN_ARRAY) {
+ in.beginArray();
+ value.append('[');
+
+ while (in.hasNext()) {
+ if (in.peek() == JsonToken.STRING) {
+ value.append('"').append(in.nextString()).append('"');
+ } else {
+ readValueObject(value, in);
+ }
+ if (in.peek() != JsonToken.END_ARRAY) {
+ value.append(',');
+ }
+ }
+
+ in.endArray();
+ value.append(']');
+ } else {
+ readValueObject(value, in);
+ }
+ }
+
+ if (in.peek() != JsonToken.END_OBJECT) {
+ value.append(',');
+ }
+ }
+
+ in.endObject();
+ value.append('}');
+ }
+
+ /**
+ * Read patch edit data defined in value node to NormalizedNode.
+ * @param in reader JsonReader reader
+ * @return NormalizedNode representing data
+ */
+ private static NormalizedNode readEditData(final @NonNull JsonReader in,
+ final @NonNull Inference targetSchemaNode, final @NonNull InstanceIdentifierContext path) {
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final EffectiveModelContext context = path.getSchemaContext();
+ JsonParserStream.create(writer, JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(context),
+ targetSchemaNode)
+ .parse(in);
+
+ return resultHolder.getResult();
+ }
+
+ /**
+ * Prepare PatchEntity from PatchEdit instance when it satisfies conditions, otherwise throws exception.
+ * @param edit Instance of PatchEdit
+ * @return PatchEntity Patch entity
+ */
+ private static PatchEntity prepareEditOperation(final @NonNull PatchEdit edit) {
+ if (edit.getOperation() != null && edit.getTargetSchemaNode() != null
+ && checkDataPresence(edit.getOperation(), edit.getData() != null)) {
+ if (edit.getOperation().isWithValue()) {
+ // for lists allow to manipulate with list items through their parent
+ final YangInstanceIdentifier targetNode;
+ if (edit.getTarget().getLastPathArgument() instanceof NodeIdentifierWithPredicates) {
+ targetNode = edit.getTarget().getParent();
+ } else {
+ targetNode = edit.getTarget();
+ }
+
+ return new PatchEntity(edit.getId(), edit.getOperation(), targetNode, edit.getData());
+ }
+
+ return new PatchEntity(edit.getId(), edit.getOperation(), edit.getTarget());
+ }
+
+ throw new RestconfDocumentedException("Error parsing input", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ }
+
+ /**
+ * Check if data is present when operation requires it and not present when operation data is not allowed.
+ * @param operation Name of operation
+ * @param hasData Data in edit are present/not present
+ * @return true if data is present when operation requires it or if there are no data when operation does not
+ * allow it, false otherwise
+ */
+ private static boolean checkDataPresence(final @NonNull PatchEditOperation operation, final boolean hasData) {
+ return operation.isWithValue() == hasData;
+ }
+
+ /**
+ * Helper class representing one patch edit.
+ */
+ private static final class PatchEdit {
+ private String id;
+ private PatchEditOperation operation;
+ private YangInstanceIdentifier target;
+ private Inference targetSchemaNode;
+ private NormalizedNode data;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ public PatchEditOperation getOperation() {
+ return operation;
+ }
+
+ public void setOperation(final PatchEditOperation operation) {
+ this.operation = operation;
+ }
+
+ public YangInstanceIdentifier getTarget() {
+ return target;
+ }
+
+ public void setTarget(final YangInstanceIdentifier target) {
+ this.target = target;
+ }
+
+ public Inference getTargetSchemaNode() {
+ return targetSchemaNode;
+ }
+
+ public void setTargetSchemaNode(final Inference targetSchemaNode) {
+ this.targetSchemaNode = targetSchemaNode;
+ }
+
+ public NormalizedNode getData() {
+ return data;
+ }
+
+ public void setData(final NormalizedNode data) {
+ this.data = data;
+ }
+
+ public void clear() {
+ id = null;
+ operation = null;
+ target = null;
+ targetSchemaNode = null;
+ data = null;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeContext.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeContext.java
new file mode 100644
index 0000000..d52de7d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeContext.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableMap;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+@Deprecated(forRemoval = true, since = "2.0.6")
+// Non-final for mocking
+public class NormalizedNodeContext {
+ private final InstanceIdentifierContext context;
+ private final ImmutableMap<String, Object> headers;
+ private final WriterParameters writerParameters;
+ private final NormalizedNode data;
+
+ public NormalizedNodeContext(final InstanceIdentifierContext context,
+ final NormalizedNode data, final WriterParameters writerParameters,
+ final ImmutableMap<String, Object> headers) {
+ this.context = context;
+ this.data = data;
+ this.writerParameters = writerParameters;
+ this.headers = requireNonNull(headers);
+ }
+
+ public NormalizedNodeContext(final InstanceIdentifierContext context,
+ final NormalizedNode data, final WriterParameters writerParameters) {
+ this(context, data, writerParameters, ImmutableMap.of());
+ }
+
+ public NormalizedNodeContext(final InstanceIdentifierContext context,
+ final NormalizedNode data) {
+ this(context, data, WriterParameters.EMPTY, ImmutableMap.of());
+ }
+
+ public NormalizedNodeContext(final InstanceIdentifierContext context,
+ final NormalizedNode data, final ImmutableMap<String, Object> headers) {
+ this(context, data, WriterParameters.EMPTY, headers);
+ }
+
+ public InstanceIdentifierContext getInstanceIdentifierContext() {
+ return context;
+ }
+
+ public NormalizedNode getData() {
+ return data;
+ }
+
+ public WriterParameters getWriterParameters() {
+ return writerParameters;
+ }
+
+ /**
+ * Return headers of {@code NormalizedNodeContext}.
+ *
+ * @return map of headers
+ */
+ public ImmutableMap<String, Object> getNewHeaders() {
+ return headers;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeJsonBodyWriter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeJsonBodyWriter.java
new file mode 100644
index 0000000..f754df8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeJsonBodyWriter.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.util.Map.Entry;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import javax.xml.stream.XMLStreamException;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfNormalizedNodeWriter;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.util.NetconfUtil;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DOMSourceAnyxmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
+import org.xml.sax.SAXException;
+
+/**
+ * Normalized node writer for JSON.
+ *
+ * @deprecated This class will be replaced by NormalizedNodeJsonBodyWriter from restconf-nb-rfc8040
+ */
+@Deprecated
+@Provider
+@Produces({
+ Draft02.MediaTypes.API + RestconfService.JSON,
+ Draft02.MediaTypes.DATA + RestconfService.JSON,
+ Draft02.MediaTypes.OPERATION + RestconfService.JSON,
+ MediaType.APPLICATION_JSON
+})
+public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<NormalizedNodeContext> {
+
+ private static final int DEFAULT_INDENT_SPACES_NUM = 2;
+
+ @Override
+ public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+ final MediaType mediaType) {
+ return type.equals(NormalizedNodeContext.class);
+ }
+
+ @Override
+ public long getSize(final NormalizedNodeContext context, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public void writeTo(final NormalizedNodeContext context, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders,
+ final OutputStream entityStream) throws IOException, WebApplicationException {
+ if (httpHeaders != null) {
+ for (final Entry<String, Object> entry : context.getNewHeaders().entrySet()) {
+ httpHeaders.add(entry.getKey(), entry.getValue());
+ }
+ }
+ NormalizedNode data = context.getData();
+ if (data == null) {
+ return;
+ }
+
+ final InstanceIdentifierContext identifierCtx = context.getInstanceIdentifierContext();
+
+ try (JsonWriter jsonWriter = createJsonWriter(entityStream, context.getWriterParameters().isPrettyPrint())) {
+ jsonWriter.beginObject();
+ writeNormalizedNode(jsonWriter, identifierCtx, data, context.getWriterParameters().getDepth());
+ jsonWriter.endObject();
+ jsonWriter.flush();
+ }
+ }
+
+ private static void writeNormalizedNode(final JsonWriter jsonWriter, final InstanceIdentifierContext context,
+ // Note: mutable argument
+ NormalizedNode data, final @Nullable Integer depth) throws IOException {
+
+ final var stack = context.inference().toSchemaInferenceStack();
+ final RestconfNormalizedNodeWriter nnWriter;
+ if (stack.isEmpty()) {
+ /*
+ * Creates writer without initialNs and we write children of root data container
+ * which is not visible in restconf
+ */
+ nnWriter = createNormalizedNodeWriter(context, context.inference(), jsonWriter, depth);
+ if (data instanceof ContainerNode) {
+ writeChildren(nnWriter,(ContainerNode) data);
+ } else if (data instanceof DOMSourceAnyxmlNode) {
+ try {
+ writeChildren(nnWriter,
+ (ContainerNode) NetconfUtil.transformDOMSourceToNormalizedNode(
+ context.getSchemaContext(), ((DOMSourceAnyxmlNode)data).body()).getResult());
+ } catch (XMLStreamException | URISyntaxException | SAXException e) {
+ throw new IOException("Cannot write anyxml.", e);
+ }
+ }
+ } else if (context.getSchemaNode() instanceof RpcDefinition) {
+ /*
+ * RpcDefinition is not supported as initial codec in JSONStreamWriter,
+ * so we need to emit initial output declaratation..
+ */
+ final var rpc = (RpcDefinition) context.getSchemaNode();
+ final var tmp = SchemaInferenceStack.of(context.getSchemaContext());
+ tmp.enterSchemaTree(rpc.getQName());
+ tmp.enterSchemaTree(rpc.getOutput().getQName());
+
+ nnWriter = createNormalizedNodeWriter(context, tmp.toInference(), jsonWriter, depth);
+ jsonWriter.name("output");
+ jsonWriter.beginObject();
+ writeChildren(nnWriter, (ContainerNode) data);
+ jsonWriter.endObject();
+ } else {
+ stack.exit();
+
+ if (data instanceof MapEntryNode) {
+ data = ImmutableNodes.mapNodeBuilder(data.getIdentifier().getNodeType())
+ .withChild((MapEntryNode) data)
+ .build();
+ }
+ nnWriter = createNormalizedNodeWriter(context, stack.toInference(), jsonWriter, depth);
+ nnWriter.write(data);
+ }
+ nnWriter.flush();
+ }
+
+ private static void writeChildren(final RestconfNormalizedNodeWriter nnWriter, final ContainerNode data)
+ throws IOException {
+ for (final DataContainerChild child : data.body()) {
+ nnWriter.write(child);
+ }
+ }
+
+ private static RestconfNormalizedNodeWriter createNormalizedNodeWriter(
+ final InstanceIdentifierContext context, final Inference inference, final JsonWriter jsonWriter,
+ final @Nullable Integer depth) {
+
+ final SchemaNode schema = context.getSchemaNode();
+ final JSONCodecFactory codecs = getCodecFactory(context);
+
+ final XMLNamespace initialNs;
+ if (schema instanceof DataSchemaNode && !((DataSchemaNode)schema).isAugmenting()
+ && !(schema instanceof SchemaContext) || schema instanceof RpcDefinition) {
+ initialNs = schema.getQName().getNamespace();
+ } else {
+ initialNs = null;
+ }
+ final NormalizedNodeStreamWriter streamWriter =
+ JSONNormalizedNodeStreamWriter.createNestedWriter(codecs, inference, initialNs, jsonWriter);
+ if (depth != null) {
+ return DepthAwareNormalizedNodeWriter.forStreamWriter(streamWriter, depth);
+ }
+
+ return RestconfDelegatingNormalizedNodeWriter.forStreamWriter(streamWriter);
+ }
+
+ private static JsonWriter createJsonWriter(final OutputStream entityStream, final boolean prettyPrint) {
+ if (prettyPrint) {
+ return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, StandardCharsets.UTF_8),
+ DEFAULT_INDENT_SPACES_NUM);
+ }
+
+ return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, StandardCharsets.UTF_8));
+ }
+
+ private static JSONCodecFactory getCodecFactory(final InstanceIdentifierContext context) {
+ // TODO: Performance: Cache JSON Codec factory and schema context
+ return JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(context.getSchemaContext());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeXmlBodyWriter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeXmlBodyWriter.java
new file mode 100644
index 0000000..e0ba9d9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/NormalizedNodeXmlBodyWriter.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.util.Map.Entry;
+import javanet.staxutils.IndentingXMLStreamWriter;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import javax.xml.XMLConstants;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfNormalizedNodeWriter;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.util.NetconfUtil;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DOMSourceAnyxmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
+import org.xml.sax.SAXException;
+
+/**
+ * Normalized node writer for XML.
+ *
+ * @deprecated This class will be replaced by NormalizedNodeXmlBodyWriter from restconf-nb-rfc8040
+ */
+@Deprecated
+@Provider
+@Produces({
+ Draft02.MediaTypes.API + RestconfService.XML,
+ Draft02.MediaTypes.DATA + RestconfService.XML,
+ Draft02.MediaTypes.OPERATION + RestconfService.XML,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+})
+public class NormalizedNodeXmlBodyWriter implements MessageBodyWriter<NormalizedNodeContext> {
+
+ private static final XMLOutputFactory XML_FACTORY;
+
+ static {
+ XML_FACTORY = XMLOutputFactory.newFactory();
+ XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+ }
+
+ @Override
+ public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+ final MediaType mediaType) {
+ return type.equals(NormalizedNodeContext.class);
+ }
+
+ @Override
+ public long getSize(final NormalizedNodeContext context, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public void writeTo(final NormalizedNodeContext context, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream) throws IOException,
+ WebApplicationException {
+ for (final Entry<String, Object> entry : context.getNewHeaders().entrySet()) {
+ httpHeaders.add(entry.getKey(), entry.getValue());
+ }
+ final InstanceIdentifierContext pathContext = context.getInstanceIdentifierContext();
+ if (context.getData() == null) {
+ return;
+ }
+
+ XMLStreamWriter xmlWriter;
+ try {
+ xmlWriter = XML_FACTORY.createXMLStreamWriter(entityStream, StandardCharsets.UTF_8.name());
+ if (context.getWriterParameters().isPrettyPrint()) {
+ xmlWriter = new IndentingXMLStreamWriter(xmlWriter);
+ }
+ } catch (final XMLStreamException | FactoryConfigurationError e) {
+ throw new IllegalStateException(e);
+ }
+ final NormalizedNode data = context.getData();
+
+ writeNormalizedNode(xmlWriter, pathContext.inference().toSchemaInferenceStack(), pathContext, data,
+ context.getWriterParameters().getDepth());
+ }
+
+ private static void writeNormalizedNode(final XMLStreamWriter xmlWriter, final SchemaInferenceStack stack,
+ final InstanceIdentifierContext pathContext, NormalizedNode data, final @Nullable Integer depth)
+ throws IOException {
+ final RestconfNormalizedNodeWriter nnWriter;
+ final EffectiveModelContext schemaCtx = pathContext.getSchemaContext();
+ if (stack.isEmpty()) {
+ nnWriter = createNormalizedNodeWriter(xmlWriter, pathContext.inference(), depth);
+ if (data instanceof DOMSourceAnyxmlNode) {
+ try {
+ writeElements(xmlWriter, nnWriter,
+ (ContainerNode) NetconfUtil.transformDOMSourceToNormalizedNode(schemaCtx,
+ ((DOMSourceAnyxmlNode)data).body()).getResult());
+ } catch (XMLStreamException | URISyntaxException | SAXException e) {
+ throw new IOException("Cannot write anyxml", e);
+ }
+ } else {
+ writeElements(xmlWriter, nnWriter, (ContainerNode) data);
+ }
+ } else if (pathContext.getSchemaNode() instanceof RpcDefinition) {
+ final var rpc = (RpcDefinition) pathContext.getSchemaNode();
+ final var tmp = SchemaInferenceStack.of(pathContext.getSchemaContext());
+ tmp.enterSchemaTree(rpc.getQName());
+ tmp.enterSchemaTree(rpc.getOutput().getQName());
+
+ nnWriter = createNormalizedNodeWriter(xmlWriter, tmp.toInference(), depth);
+ writeElements(xmlWriter, nnWriter, (ContainerNode) data);
+ } else {
+ stack.exit();
+ nnWriter = createNormalizedNodeWriter(xmlWriter, stack.toInference(), depth);
+ if (data instanceof MapEntryNode) {
+ // Restconf allows returning one list item. We need to wrap it
+ // in map node in order to serialize it properly
+ data = ImmutableNodes.mapNodeBuilder(data.getIdentifier().getNodeType())
+ .addChild((MapEntryNode) data)
+ .build();
+ }
+ nnWriter.write(data);
+ }
+ nnWriter.flush();
+ }
+
+ private static RestconfNormalizedNodeWriter createNormalizedNodeWriter(final XMLStreamWriter xmlWriter,
+ final Inference inference, final @Nullable Integer depth) {
+ final NormalizedNodeStreamWriter xmlStreamWriter =
+ XMLStreamNormalizedNodeStreamWriter.create(xmlWriter, inference);
+ if (depth != null) {
+ return DepthAwareNormalizedNodeWriter.forStreamWriter(xmlStreamWriter, depth);
+ }
+
+ return RestconfDelegatingNormalizedNodeWriter.forStreamWriter(xmlStreamWriter);
+ }
+
+ private static void writeElements(final XMLStreamWriter xmlWriter, final RestconfNormalizedNodeWriter nnWriter,
+ final ContainerNode data) throws IOException {
+ final QName name = data.getIdentifier().getNodeType();
+ try {
+ xmlWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, name.getLocalName(),
+ name.getNamespace().toString());
+ xmlWriter.writeDefaultNamespace(name.getNamespace().toString());
+ for (final NormalizedNode child : data.body()) {
+ nnWriter.write(child);
+ }
+ nnWriter.flush();
+ xmlWriter.writeEndElement();
+ xmlWriter.flush();
+ } catch (final XMLStreamException e) {
+ throw new IOException("Failed to write elements", e);
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/PatchJsonBodyWriter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/PatchJsonBodyWriter.java
new file mode 100644
index 0000000..63586af
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/PatchJsonBodyWriter.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.sal.rest.impl;
+
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.restconf.common.patch.PatchStatusEntity;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
+
+
+@Provider
+@Produces({ Draft02.MediaTypes.PATCH_STATUS + RestconfService.JSON })
+public class PatchJsonBodyWriter implements MessageBodyWriter<PatchStatusContext> {
+
+ @Override
+ public boolean isWriteable(final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
+ return type.equals(PatchStatusContext.class);
+ }
+
+ @Override
+ public long getSize(final PatchStatusContext patchStatusContext, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public void writeTo(final PatchStatusContext patchStatusContext, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream)
+ throws IOException, WebApplicationException {
+
+ final JsonWriter jsonWriter = createJsonWriter(entityStream);
+ jsonWriter.beginObject().name("ietf-yang-patch:yang-patch-status");
+ jsonWriter.beginObject();
+ jsonWriter.name("patch-id").value(patchStatusContext.getPatchId());
+ if (patchStatusContext.isOk()) {
+ reportSuccess(jsonWriter);
+ } else {
+ if (patchStatusContext.getGlobalErrors() != null) {
+ reportErrors(patchStatusContext.getGlobalErrors(), jsonWriter);
+ }
+
+ jsonWriter.name("edit-status");
+ jsonWriter.beginObject();
+ jsonWriter.name("edit");
+ jsonWriter.beginArray();
+ for (final PatchStatusEntity patchStatusEntity : patchStatusContext.getEditCollection()) {
+ jsonWriter.beginObject();
+ jsonWriter.name("edit-id").value(patchStatusEntity.getEditId());
+ if (patchStatusEntity.getEditErrors() != null) {
+ reportErrors(patchStatusEntity.getEditErrors(), jsonWriter);
+ } else {
+ if (patchStatusEntity.isOk()) {
+ reportSuccess(jsonWriter);
+ }
+ }
+ jsonWriter.endObject();
+ }
+ jsonWriter.endArray();
+ jsonWriter.endObject();
+ }
+ jsonWriter.endObject();
+ jsonWriter.endObject();
+ jsonWriter.flush();
+ }
+
+ private static void reportSuccess(final JsonWriter jsonWriter) throws IOException {
+ jsonWriter.name("ok").beginArray().nullValue().endArray();
+ }
+
+ private static void reportErrors(final List<RestconfError> errors, final JsonWriter jsonWriter) throws IOException {
+ jsonWriter.name("errors");
+ jsonWriter.beginObject();
+ jsonWriter.name("error");
+ jsonWriter.beginArray();
+
+ for (final RestconfError restconfError : errors) {
+ jsonWriter.beginObject();
+ jsonWriter.name("error-type").value(restconfError.getErrorType().elementBody());
+ jsonWriter.name("error-tag").value(restconfError.getErrorTag().elementBody());
+
+ // optional node
+ if (restconfError.getErrorPath() != null) {
+ jsonWriter.name("error-path").value(restconfError.getErrorPath().toString());
+ }
+
+ // optional node
+ if (restconfError.getErrorMessage() != null) {
+ jsonWriter.name("error-message").value(restconfError.getErrorMessage());
+ }
+
+ // optional node
+ if (restconfError.getErrorInfo() != null) {
+ jsonWriter.name("error-info").value(restconfError.getErrorInfo());
+ }
+
+ jsonWriter.endObject();
+ }
+
+ jsonWriter.endArray();
+ jsonWriter.endObject();
+ }
+
+ private static JsonWriter createJsonWriter(final OutputStream entityStream) {
+ return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, StandardCharsets.UTF_8));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/PatchXmlBodyWriter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/PatchXmlBodyWriter.java
new file mode 100644
index 0000000..d941d6c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/PatchXmlBodyWriter.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.sal.rest.impl;
+
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.restconf.common.patch.PatchStatusEntity;
+
+@Provider
+@Produces({ Draft02.MediaTypes.PATCH_STATUS + RestconfService.XML })
+public class PatchXmlBodyWriter implements MessageBodyWriter<PatchStatusContext> {
+
+ private static final XMLOutputFactory XML_FACTORY;
+
+ static {
+ XML_FACTORY = XMLOutputFactory.newFactory();
+ XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+ }
+
+ @Override
+ public boolean isWriteable(final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
+ return type.equals(PatchStatusContext.class);
+ }
+
+ @Override
+ public long getSize(final PatchStatusContext patchStatusContext, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public void writeTo(final PatchStatusContext patchStatusContext, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream)
+ throws WebApplicationException {
+
+ try {
+ final XMLStreamWriter xmlWriter =
+ XML_FACTORY.createXMLStreamWriter(entityStream, StandardCharsets.UTF_8.name());
+ writeDocument(xmlWriter, patchStatusContext);
+ } catch (final XMLStreamException | FactoryConfigurationError e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private static void writeDocument(final XMLStreamWriter writer, final PatchStatusContext context)
+ throws XMLStreamException {
+ writer.writeStartElement("", "yang-patch-status", "urn:ietf:params:xml:ns:yang:ietf-yang-patch");
+ writer.writeStartElement("patch-id");
+ writer.writeCharacters(context.getPatchId());
+ writer.writeEndElement();
+
+ if (context.isOk()) {
+ writer.writeEmptyElement("ok");
+ } else {
+ if (context.getGlobalErrors() != null) {
+ reportErrors(context.getGlobalErrors(), writer);
+ }
+ writer.writeStartElement("edit-status");
+ for (final PatchStatusEntity patchStatusEntity : context.getEditCollection()) {
+ writer.writeStartElement("edit");
+ writer.writeStartElement("edit-id");
+ writer.writeCharacters(patchStatusEntity.getEditId());
+ writer.writeEndElement();
+ if (patchStatusEntity.getEditErrors() != null) {
+ reportErrors(patchStatusEntity.getEditErrors(), writer);
+ } else {
+ if (patchStatusEntity.isOk()) {
+ writer.writeEmptyElement("ok");
+ }
+ }
+ writer.writeEndElement();
+ }
+ writer.writeEndElement();
+
+ }
+ writer.writeEndElement();
+
+ writer.flush();
+ }
+
+ private static void reportErrors(final List<RestconfError> errors, final XMLStreamWriter writer)
+ throws XMLStreamException {
+ writer.writeStartElement("errors");
+
+ for (final RestconfError restconfError : errors) {
+ writer.writeStartElement("error-type");
+ writer.writeCharacters(restconfError.getErrorType().elementBody());
+ writer.writeEndElement();
+
+ writer.writeStartElement("error-tag");
+ writer.writeCharacters(restconfError.getErrorTag().elementBody());
+ writer.writeEndElement();
+
+ // optional node
+ if (restconfError.getErrorPath() != null) {
+ writer.writeStartElement("error-path");
+ writer.writeCharacters(restconfError.getErrorPath().toString());
+ writer.writeEndElement();
+ }
+
+ // optional node
+ if (restconfError.getErrorMessage() != null) {
+ writer.writeStartElement("error-message");
+ writer.writeCharacters(restconfError.getErrorMessage());
+ writer.writeEndElement();
+ }
+
+ // optional node
+ if (restconfError.getErrorInfo() != null) {
+ writer.writeStartElement("error-info");
+ writer.writeCharacters(restconfError.getErrorInfo());
+ writer.writeEndElement();
+ }
+ }
+
+ writer.writeEndElement();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfApplication.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfApplication.java
new file mode 100644
index 0000000..d8918df
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfApplication.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.HashSet;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.core.Application;
+import org.opendaylight.netconf.md.sal.rest.schema.SchemaExportContentYangBodyWriter;
+import org.opendaylight.netconf.md.sal.rest.schema.SchemaExportContentYinBodyWriter;
+import org.opendaylight.netconf.md.sal.rest.schema.SchemaRetrievalServiceImpl;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.StatisticsRestconfServiceWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+@Deprecated(since = "2.0.12")
+public class RestconfApplication extends Application {
+ private static final Logger LOG = LoggerFactory.getLogger(RestconfApplication.class);
+
+ private final ControllerContext controllerContext;
+ private final StatisticsRestconfServiceWrapper statsServiceWrapper;
+
+ @Inject
+ public RestconfApplication(final ControllerContext controllerContext,
+ final StatisticsRestconfServiceWrapper statsServiceWrapper) {
+ this.controllerContext = controllerContext;
+ this.statsServiceWrapper = statsServiceWrapper;
+ LOG.warn("Pre-standard version of RESTCONF activated. Please note that this implementation is considered "
+ + "obsoleve and WILL BE REMOVED IN THE NEXT MAJOR RELEASE. Please use the RFC8040-compliant "
+ + "implementation instead.");
+ }
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ return ImmutableSet.<Class<?>>builder()
+ .add(PatchJsonBodyWriter.class)
+ .add(PatchXmlBodyWriter.class)
+ .add(NormalizedNodeJsonBodyWriter.class)
+ .add(NormalizedNodeXmlBodyWriter.class)
+ .add(SchemaExportContentYinBodyWriter.class)
+ .add(SchemaExportContentYangBodyWriter.class)
+ .build();
+ }
+
+ @Override
+ public Set<Object> getSingletons() {
+ final Set<Object> singletons = new HashSet<>();
+ final SchemaRetrievalServiceImpl schemaRetrieval = new SchemaRetrievalServiceImpl(controllerContext);
+ singletons.add(schemaRetrieval);
+ singletons.add(new RestconfCompositeWrapper(statsServiceWrapper, schemaRetrieval));
+ singletons.add(new RestconfDocumentedExceptionMapper(controllerContext));
+ singletons.add(new XmlNormalizedNodeBodyReader(controllerContext));
+ singletons.add(new JsonNormalizedNodeBodyReader(controllerContext));
+ singletons.add(new XmlToPatchBodyReader(controllerContext));
+ singletons.add(new JsonToPatchBodyReader(controllerContext));
+// singletons.add(StructuredDataToXmlProvider.INSTANCE);
+// singletons.add(StructuredDataToJsonProvider.INSTANCE);
+// singletons.add(JsonToCompositeNodeProvider.INSTANCE);
+// singletons.add(XmlToCompositeNodeProvider.INSTANCE);
+ return singletons;
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfCompositeWrapper.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfCompositeWrapper.java
new file mode 100644
index 0000000..90b83a0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfCompositeWrapper.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.netconf.md.sal.rest.schema.SchemaRetrievalService;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.restconf.common.schema.SchemaExportContext;
+
+public class RestconfCompositeWrapper implements RestconfService, SchemaRetrievalService {
+
+ private final RestconfService restconf;
+ private final SchemaRetrievalService schema;
+
+ public RestconfCompositeWrapper(final RestconfService restconf, final SchemaRetrievalService schema) {
+ this.restconf = requireNonNull(restconf);
+ this.schema = requireNonNull(schema);
+ }
+
+ @Override
+ public Object getRoot() {
+ return this.restconf.getRoot();
+ }
+
+ @Override
+ public NormalizedNodeContext getModules(final UriInfo uriInfo) {
+ return this.restconf.getModules(uriInfo);
+ }
+
+ @Override
+ public NormalizedNodeContext getModules(final String identifier, final UriInfo uriInfo) {
+ return this.restconf.getModules(identifier, uriInfo);
+ }
+
+ @Override
+ public NormalizedNodeContext getModule(final String identifier, final UriInfo uriInfo) {
+ return this.restconf.getModule(identifier, uriInfo);
+ }
+
+ @Override
+ public String getOperationsJSON() {
+ return this.restconf.getOperationsJSON();
+ }
+
+ @Override
+ public String getOperationsXML() {
+ return this.restconf.getOperationsXML();
+ }
+
+ @Override
+ public NormalizedNodeContext getOperations(final String identifier, final UriInfo uriInfo) {
+ return this.restconf.getOperations(identifier, uriInfo);
+ }
+
+ @Override
+ public NormalizedNodeContext invokeRpc(final String identifier, final NormalizedNodeContext payload,
+ final UriInfo uriInfo) {
+ return this.restconf.invokeRpc(identifier, payload, uriInfo);
+ }
+
+ @Override
+ public NormalizedNodeContext readConfigurationData(final String identifier, final UriInfo uriInfo) {
+ return this.restconf.readConfigurationData(identifier, uriInfo);
+ }
+
+ @Override
+ public NormalizedNodeContext readOperationalData(final String identifier, final UriInfo uriInfo) {
+ return this.restconf.readOperationalData(identifier, uriInfo);
+ }
+
+ @Override
+ public Response updateConfigurationData(final String identifier, final NormalizedNodeContext payload,
+ final UriInfo uriInfo) {
+ return this.restconf.updateConfigurationData(identifier, payload, uriInfo);
+ }
+
+ @Override
+ public Response createConfigurationData(final String identifier, final NormalizedNodeContext payload,
+ final UriInfo uriInfo) {
+ return this.restconf.createConfigurationData(identifier, payload, uriInfo);
+ }
+
+ @Override
+ public Response createConfigurationData(final NormalizedNodeContext payload, final UriInfo uriInfo) {
+ return this.restconf.createConfigurationData(payload, uriInfo);
+ }
+
+ @Override
+ public Response deleteConfigurationData(final String identifier) {
+ return this.restconf.deleteConfigurationData(identifier);
+ }
+
+ @Override
+ public NormalizedNodeContext subscribeToStream(final String identifier, final UriInfo uriInfo) {
+ return this.restconf.subscribeToStream(identifier, uriInfo);
+ }
+
+ @Override
+ public NormalizedNodeContext getAvailableStreams(final UriInfo uriInfo) {
+ return this.restconf.getAvailableStreams(uriInfo);
+ }
+
+ @Override
+ public PatchStatusContext patchConfigurationData(final String identifier, final PatchContext payload,
+ final UriInfo uriInfo) {
+ return this.restconf.patchConfigurationData(identifier, payload, uriInfo);
+ }
+
+ @Override
+ public PatchStatusContext patchConfigurationData(final PatchContext context, final UriInfo uriInfo) {
+ return this.restconf.patchConfigurationData(context, uriInfo);
+ }
+
+ @Override
+ public SchemaExportContext getSchema(final String mountId) {
+ return this.schema.getSchema(mountId);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfDelegatingNormalizedNodeWriter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfDelegatingNormalizedNodeWriter.java
new file mode 100644
index 0000000..aaa1ccc
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfDelegatingNormalizedNodeWriter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import java.io.IOException;
+import org.opendaylight.netconf.sal.rest.api.RestconfNormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+
+/**
+ * This class just delegates all of the functionality to Yangtools normalized node writer.
+ */
+public final class RestconfDelegatingNormalizedNodeWriter implements RestconfNormalizedNodeWriter {
+ private final NormalizedNodeWriter delegNNWriter;
+
+ private RestconfDelegatingNormalizedNodeWriter(final NormalizedNodeStreamWriter streamWriter, final boolean
+ orderKeyLeaves) {
+ this.delegNNWriter = NormalizedNodeWriter.forStreamWriter(streamWriter, orderKeyLeaves);
+ }
+
+ public static RestconfDelegatingNormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer) {
+ return forStreamWriter(writer, true);
+ }
+
+ public static RestconfDelegatingNormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
+ final boolean orderKeyLeaves) {
+ return new RestconfDelegatingNormalizedNodeWriter(writer, orderKeyLeaves);
+ }
+
+ @Override
+ public RestconfDelegatingNormalizedNodeWriter write(final NormalizedNode node) throws IOException {
+ delegNNWriter.write(node);
+ return this;
+ }
+
+ @Override
+ public void flush() throws IOException {
+ delegNNWriter.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ delegNNWriter.close();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfDocumentedExceptionMapper.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfDocumentedExceptionMapper.java
new file mode 100644
index 0000000..ff0be39
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/RestconfDocumentedExceptionMapper.java
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+import com.google.gson.stream.JsonWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import javax.xml.XMLConstants;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.ErrorTags;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.ForwardingNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
+import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class defines an ExceptionMapper that handles RestconfDocumentedExceptions thrown by resource implementations
+ * and translates appropriately to restconf error response as defined in the RESTCONF RFC draft.
+ *
+ * @author Thomas Pantelis
+ */
+@Provider
+public class RestconfDocumentedExceptionMapper implements ExceptionMapper<RestconfDocumentedException> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RestconfDocumentedExceptionMapper.class);
+
+ private static final XMLOutputFactory XML_FACTORY;
+
+ static {
+ XML_FACTORY = XMLOutputFactory.newFactory();
+ XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+ }
+
+ @Context
+ private HttpHeaders headers;
+
+ private final ControllerContext controllerContext;
+
+ public RestconfDocumentedExceptionMapper(final ControllerContext controllerContext) {
+ this.controllerContext = requireNonNull(controllerContext);
+ }
+
+ @Override
+ public Response toResponse(final RestconfDocumentedException exception) {
+
+ LOG.debug("In toResponse: {}", exception.getMessage());
+
+ final List<MediaType> mediaTypeList = new ArrayList<>();
+ if (headers.getMediaType() != null) {
+ mediaTypeList.add(headers.getMediaType());
+ }
+
+ mediaTypeList.addAll(headers.getAcceptableMediaTypes());
+ final MediaType mediaType = mediaTypeList.stream().filter(type -> !type.equals(MediaType.WILDCARD_TYPE))
+ .findFirst().orElse(MediaType.APPLICATION_JSON_TYPE);
+
+ LOG.debug("Using MediaType: {}", mediaType);
+
+ final List<RestconfError> errors = exception.getErrors();
+ if (errors.isEmpty()) {
+ // We don't actually want to send any content but, if we don't set any content here,
+ // the tomcat front-end will send back an html error report. To prevent that, set a
+ // single space char in the entity.
+
+ return Response.status(exception.getStatus()).type(MediaType.TEXT_PLAIN_TYPE).entity(" ").build();
+ }
+
+ final Status status = ErrorTags.statusOf(errors.iterator().next().getErrorTag());
+ final var errorsEntry = controllerContext.getRestconfModuleErrorsSchemaNode();
+ if (errorsEntry == null) {
+ return Response.status(status).type(MediaType.TEXT_PLAIN_TYPE).entity(exception.getMessage()).build();
+ }
+
+ final var errorsSchemaNode = errorsEntry.getValue();
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> errContBuild =
+ SchemaAwareBuilders.containerBuilder(errorsSchemaNode);
+
+ final var schemaList = ControllerContext.findInstanceDataChildrenByName(errorsSchemaNode,
+ Draft02.RestConfModule.ERROR_LIST_SCHEMA_NODE);
+ final DataSchemaNode errListSchemaNode = ControllerContext.getFirst(schemaList);
+ checkState(errListSchemaNode instanceof ListSchemaNode, "Found Error SchemaNode isn't ListSchemaNode");
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> listErorsBuilder = SchemaAwareBuilders
+ .mapBuilder((ListSchemaNode) errListSchemaNode);
+
+
+ for (final RestconfError error : errors) {
+ listErorsBuilder.withChild(toErrorEntryNode(error, errListSchemaNode));
+ }
+ errContBuild.withChild(listErorsBuilder.build());
+
+ final NormalizedNodeContext errContext = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(errorsEntry.getKey(), null), errContBuild.build());
+
+ final String responseBody;
+ if (mediaType.getSubtype().endsWith("json")) {
+ responseBody = toJsonResponseBody(errContext);
+ } else {
+ responseBody = toXMLResponseBody(errContext);
+ }
+
+ return Response.status(status).type(mediaType).entity(responseBody).build();
+ }
+
+ private static MapEntryNode toErrorEntryNode(final RestconfError error, final DataSchemaNode errListSchemaNode) {
+ checkArgument(errListSchemaNode instanceof ListSchemaNode,
+ "errListSchemaNode has to be of type ListSchemaNode");
+ final ListSchemaNode listStreamSchemaNode = (ListSchemaNode) errListSchemaNode;
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> errNodeValues = SchemaAwareBuilders
+ .mapEntryBuilder(listStreamSchemaNode);
+
+ var lsChildDataSchemaNode = ControllerContext.findInstanceDataChildrenByName(
+ listStreamSchemaNode, "error-type");
+ final DataSchemaNode errTypSchemaNode = ControllerContext.getFirst(lsChildDataSchemaNode);
+ checkState(errTypSchemaNode instanceof LeafSchemaNode);
+ errNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) errTypSchemaNode)
+ .withValue(error.getErrorType().elementBody()).build());
+
+ lsChildDataSchemaNode = ControllerContext.findInstanceDataChildrenByName(
+ listStreamSchemaNode, "error-tag");
+ final DataSchemaNode errTagSchemaNode = ControllerContext.getFirst(lsChildDataSchemaNode);
+ checkState(errTagSchemaNode instanceof LeafSchemaNode);
+ errNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) errTagSchemaNode)
+ .withValue(error.getErrorTag().elementBody()).build());
+
+ if (error.getErrorAppTag() != null) {
+ lsChildDataSchemaNode = ControllerContext.findInstanceDataChildrenByName(
+ listStreamSchemaNode, "error-app-tag");
+ final DataSchemaNode errAppTagSchemaNode = ControllerContext.getFirst(lsChildDataSchemaNode);
+ checkState(errAppTagSchemaNode instanceof LeafSchemaNode);
+ errNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) errAppTagSchemaNode)
+ .withValue(error.getErrorAppTag()).build());
+ }
+
+ lsChildDataSchemaNode = ControllerContext.findInstanceDataChildrenByName(
+ listStreamSchemaNode, "error-message");
+ final DataSchemaNode errMsgSchemaNode = ControllerContext.getFirst(lsChildDataSchemaNode);
+ checkState(errMsgSchemaNode instanceof LeafSchemaNode);
+ errNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) errMsgSchemaNode)
+ .withValue(error.getErrorMessage()).build());
+
+ if (error.getErrorInfo() != null) {
+ // Oddly, error-info is defined as an empty container in the restconf yang. Apparently the
+ // intention is for implementors to define their own data content so we'll just treat it as a leaf
+ // with string data.
+ errNodeValues.withChild(ImmutableNodes.leafNode(Draft02.RestConfModule.ERROR_INFO_QNAME,
+ error.getErrorInfo()));
+ }
+
+ // TODO : find how could we add possible "error-path"
+
+ return errNodeValues.build();
+ }
+
+ private static String toJsonResponseBody(final NormalizedNodeContext errorsNode) {
+ final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ NormalizedNode data = errorsNode.getData();
+ final InstanceIdentifierContext context = errorsNode.getInstanceIdentifierContext();
+ final DataSchemaNode schema = (DataSchemaNode) context.getSchemaNode();
+
+ final OutputStreamWriter outputWriter = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);
+ if (data == null) {
+ throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
+ }
+
+ final boolean isDataRoot;
+ final var stack = context.inference().toSchemaInferenceStack();
+ if (stack.isEmpty()) {
+ isDataRoot = true;
+ } else {
+ isDataRoot = false;
+ stack.exit();
+ // FIXME: Add proper handling of reading root.
+ }
+
+ XMLNamespace initialNs = null;
+ if (!schema.isAugmenting() && !(schema instanceof SchemaContext)) {
+ initialNs = schema.getQName().getNamespace();
+ }
+
+ final JsonWriter jsonWriter = JsonWriterFactory.createJsonWriter(outputWriter);
+ final NormalizedNodeStreamWriter jsonStreamWriter = JSONNormalizedNodeStreamWriter.createExclusiveWriter(
+ JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(context.getSchemaContext()),
+ stack.toInference(), initialNs, jsonWriter);
+
+ // We create a delegating writer to special-case error-info as error-info is defined as an empty
+ // container in the restconf yang schema but we create a leaf node so we can output it. The delegate
+ // stream writer validates the node type against the schema and thus will expect a LeafSchemaNode but
+ // the schema has a ContainerSchemaNode so, to avoid an error, we override the leafNode behavior
+ // for error-info.
+ final NormalizedNodeStreamWriter streamWriter = new ForwardingNormalizedNodeStreamWriter() {
+ private boolean inOurLeaf;
+
+ @Override
+ protected NormalizedNodeStreamWriter delegate() {
+ return jsonStreamWriter;
+ }
+
+ @Override
+ public void startLeafNode(final NodeIdentifier name) throws IOException {
+ if (name.getNodeType().equals(Draft02.RestConfModule.ERROR_INFO_QNAME)) {
+ inOurLeaf = true;
+ jsonWriter.name(Draft02.RestConfModule.ERROR_INFO_QNAME.getLocalName());
+ } else {
+ super.startLeafNode(name);
+ }
+ }
+
+ @Override
+ public void scalarValue(final Object value) throws IOException {
+ if (inOurLeaf) {
+ jsonWriter.value(value.toString());
+ } else {
+ super.scalarValue(value);
+ }
+ }
+
+ @Override
+ public void endNode() throws IOException {
+ if (inOurLeaf) {
+ inOurLeaf = false;
+ } else {
+ super.endNode();
+ }
+ }
+ };
+
+ final NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(streamWriter);
+ try {
+ if (isDataRoot) {
+ writeDataRoot(outputWriter,nnWriter,(ContainerNode) data);
+ } else {
+ if (data instanceof MapEntryNode) {
+ data = ImmutableNodes.mapNodeBuilder(data.getIdentifier().getNodeType())
+ .withChild((MapEntryNode) data)
+ .build();
+ }
+ nnWriter.write(data);
+ }
+ nnWriter.flush();
+ outputWriter.flush();
+ } catch (final IOException e) {
+ LOG.warn("Error writing error response body", e);
+ }
+
+ try {
+ streamWriter.close();
+ } catch (IOException e) {
+ LOG.warn("Failed to close stream writer", e);
+ }
+
+ return outStream.toString(StandardCharsets.UTF_8);
+ }
+
+ private static String toXMLResponseBody(final NormalizedNodeContext errorsNode) {
+ final InstanceIdentifierContext pathContext = errorsNode.getInstanceIdentifierContext();
+ final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+
+ final XMLStreamWriter xmlWriter;
+ try {
+ xmlWriter = XML_FACTORY.createXMLStreamWriter(outStream, StandardCharsets.UTF_8.name());
+ } catch (final XMLStreamException | FactoryConfigurationError e) {
+ throw new IllegalStateException(e);
+ }
+ NormalizedNode data = errorsNode.getData();
+
+ final boolean isDataRoot;
+ final var stack = pathContext.inference().toSchemaInferenceStack();
+ if (stack.isEmpty()) {
+ isDataRoot = true;
+ } else {
+ isDataRoot = false;
+ stack.exit();
+ }
+
+ final NormalizedNodeStreamWriter xmlStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,
+ stack.toInference());
+
+ // We create a delegating writer to special-case error-info as error-info is defined as an empty
+ // container in the restconf yang schema but we create a leaf node so we can output it. The delegate
+ // stream writer validates the node type against the schema and thus will expect a LeafSchemaNode but
+ // the schema has a ContainerSchemaNode so, to avoid an error, we override the leafNode behavior
+ // for error-info.
+ final NormalizedNodeStreamWriter streamWriter = new ForwardingNormalizedNodeStreamWriter() {
+ private boolean inOurLeaf;
+
+ @Override
+ protected NormalizedNodeStreamWriter delegate() {
+ return xmlStreamWriter;
+ }
+
+ @Override
+ public void startLeafNode(final NodeIdentifier name) throws IOException {
+ if (name.getNodeType().equals(Draft02.RestConfModule.ERROR_INFO_QNAME)) {
+ String ns = Draft02.RestConfModule.ERROR_INFO_QNAME.getNamespace().toString();
+ try {
+ xmlWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX,
+ Draft02.RestConfModule.ERROR_INFO_QNAME.getLocalName(), ns);
+ } catch (XMLStreamException e) {
+ throw new IOException("Error writing error-info", e);
+ }
+ inOurLeaf = true;
+ } else {
+ super.startLeafNode(name);
+ }
+ }
+
+ @Override
+ public void scalarValue(final Object value) throws IOException {
+ if (inOurLeaf) {
+ try {
+ xmlWriter.writeCharacters(value.toString());
+ } catch (XMLStreamException e) {
+ throw new IOException("Error writing error-info", e);
+ }
+ } else {
+ super.scalarValue(value);
+ }
+ }
+
+ @Override
+ public void endNode() throws IOException {
+ if (inOurLeaf) {
+ try {
+ xmlWriter.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new IOException("Error writing error-info", e);
+ }
+ inOurLeaf = false;
+ } else {
+ super.endNode();
+ }
+ }
+ };
+
+ final NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(streamWriter);
+ try {
+ if (isDataRoot) {
+ writeRootElement(xmlWriter, nnWriter, (ContainerNode) data);
+ } else {
+ if (data instanceof MapEntryNode) {
+ // Restconf allows returning one list item. We need to wrap it
+ // in map node in order to serialize it properly
+ data = ImmutableNodes.mapNodeBuilder(data.getIdentifier().getNodeType())
+ .addChild((MapEntryNode) data)
+ .build();
+ }
+ nnWriter.write(data);
+ nnWriter.flush();
+ }
+ } catch (final IOException e) {
+ LOG.warn("Error writing error response body.", e);
+ }
+
+ return outStream.toString(StandardCharsets.UTF_8);
+ }
+
+ private static void writeRootElement(final XMLStreamWriter xmlWriter, final NormalizedNodeWriter nnWriter,
+ final ContainerNode data) throws IOException {
+ final QName name = SchemaContext.NAME;
+ try {
+ xmlWriter.writeStartElement(name.getNamespace().toString(), name.getLocalName());
+ for (final DataContainerChild child : data.body()) {
+ nnWriter.write(child);
+ }
+ nnWriter.flush();
+ xmlWriter.writeEndElement();
+ xmlWriter.flush();
+ } catch (final XMLStreamException e) {
+ throw new IOException("Failed to write elements", e);
+ }
+ }
+
+ private static void writeDataRoot(final OutputStreamWriter outputWriter, final NormalizedNodeWriter nnWriter,
+ final ContainerNode data) throws IOException {
+ for (final DataContainerChild child : data.body()) {
+ nnWriter.write(child);
+ nnWriter.flush();
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/StringModuleInstanceIdentifierCodec.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/StringModuleInstanceIdentifierCodec.java
new file mode 100644
index 0000000..b61ed58
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/StringModuleInstanceIdentifierCodec.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * Codec for module instance identifiers.
+ *
+ * @deprecated This class will be replaced by StringModuleInstanceIdentifierCodec from restconf-nb-rfc8040
+ */
+@Deprecated
+public final class StringModuleInstanceIdentifierCodec extends AbstractModuleStringInstanceIdentifierCodec {
+
+ private final DataSchemaContextTree dataContextTree;
+ private final SchemaContext context;
+ private final String defaultPrefix;
+
+ public StringModuleInstanceIdentifierCodec(final EffectiveModelContext context) {
+ this.context = requireNonNull(context);
+ this.dataContextTree = DataSchemaContextTree.from(context);
+ this.defaultPrefix = "";
+ }
+
+ StringModuleInstanceIdentifierCodec(final EffectiveModelContext context, final @NonNull String defaultPrefix) {
+ this.context = requireNonNull(context);
+ this.dataContextTree = DataSchemaContextTree.from(context);
+ this.defaultPrefix = defaultPrefix;
+ }
+
+ @Override
+ protected Module moduleForPrefix(final String prefix) {
+ if (prefix.isEmpty() && !this.defaultPrefix.isEmpty()) {
+ return this.context.findModules(this.defaultPrefix).stream().findFirst().orElse(null);
+ } else {
+ return this.context.findModules(prefix).stream().findFirst().orElse(null);
+ }
+ }
+
+ @Override
+ protected DataSchemaContextTree getDataContextTree() {
+ return this.dataContextTree;
+ }
+
+ @Override
+ protected String prefixForNamespace(final XMLNamespace namespace) {
+ return this.context.findModules(namespace).stream().findFirst().map(Module::getName).orElse(null);
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/UnsupportedFormatException.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/UnsupportedFormatException.java
new file mode 100644
index 0000000..9e21659
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/UnsupportedFormatException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+public class UnsupportedFormatException extends Exception {
+
+ private static final long serialVersionUID = -1741388894406313402L;
+
+ public UnsupportedFormatException() {
+ }
+
+ public UnsupportedFormatException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public UnsupportedFormatException(String message) {
+ super(message);
+ }
+
+ public UnsupportedFormatException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/WriterParameters.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/WriterParameters.java
new file mode 100644
index 0000000..1ad6985
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/WriterParameters.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+@Deprecated(forRemoval = true, since = "2.0.6")
+public final class WriterParameters {
+ static final WriterParameters EMPTY = new WriterParametersBuilder().build();
+
+ private final Integer depth;
+ private final boolean prettyPrint;
+
+ private WriterParameters(final WriterParametersBuilder builder) {
+ depth = builder.depth;
+ prettyPrint = builder.prettyPrint;
+ }
+
+ public Integer getDepth() {
+ return depth;
+ }
+
+ public boolean isPrettyPrint() {
+ return prettyPrint;
+ }
+
+ @Deprecated(forRemoval = true, since = "2.0.6")
+ public static final class WriterParametersBuilder {
+ private Integer depth;
+ private boolean prettyPrint;
+
+ public WriterParametersBuilder setDepth(final int depth) {
+ this.depth = depth;
+ return this;
+ }
+
+ public WriterParametersBuilder setPrettyPrint(final boolean prettyPrint) {
+ this.prettyPrint = prettyPrint;
+ return this;
+ }
+
+ public WriterParameters build() {
+ return new WriterParameters(this);
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlNormalizedNodeBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlNormalizedNodeBodyReader.java
new file mode 100644
index 0000000..84a7978
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlNormalizedNodeBodyReader.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.util.RestUtil;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.stmt.ListEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+@Provider
+@Consumes({
+ Draft02.MediaTypes.DATA + RestconfService.XML,
+ Draft02.MediaTypes.OPERATION + RestconfService.XML,
+ MediaType.APPLICATION_XML,
+ MediaType.TEXT_XML
+})
+public class XmlNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsProvider
+ implements MessageBodyReader<NormalizedNodeContext> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(XmlNormalizedNodeBodyReader.class);
+
+ public XmlNormalizedNodeBodyReader(final ControllerContext controllerContext) {
+ super(controllerContext);
+ }
+
+ @Override
+ public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+ final MediaType mediaType) {
+ return true;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public NormalizedNodeContext readFrom(final Class<NormalizedNodeContext> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream) throws
+ WebApplicationException {
+ try {
+ return readFrom(entityStream);
+ } catch (final RestconfDocumentedException e) {
+ throw e;
+ } catch (final Exception e) {
+ LOG.debug("Error parsing xml input", e);
+ RestconfDocumentedException.throwIfYangError(e);
+ throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE, e);
+ }
+ }
+
+ private NormalizedNodeContext readFrom(final InputStream entityStream) throws IOException, SAXException,
+ XMLStreamException, ParserConfigurationException, URISyntaxException {
+ final InstanceIdentifierContext path = getInstanceIdentifierContext();
+ final Optional<InputStream> nonEmptyInputStreamOptional = RestUtil.isInputStreamEmpty(entityStream);
+ if (nonEmptyInputStreamOptional.isEmpty()) {
+ // represent empty nopayload input
+ return new NormalizedNodeContext(path, null);
+ }
+
+ final Document doc = UntrustedXML.newDocumentBuilder().parse(nonEmptyInputStreamOptional.get());
+ return parse(path, doc);
+ }
+
+ private NormalizedNodeContext parse(final InstanceIdentifierContext pathContext,final Document doc)
+ throws XMLStreamException, IOException, SAXException, URISyntaxException {
+ final SchemaNode schemaNodeContext = pathContext.getSchemaNode();
+ DataSchemaNode schemaNode;
+ final List<PathArgument> iiToDataList = new ArrayList<>();
+ Inference inference;
+ if (schemaNodeContext instanceof RpcDefinition) {
+ schemaNode = ((RpcDefinition) schemaNodeContext).getInput();
+ inference = pathContext.inference();
+ } else if (schemaNodeContext instanceof DataSchemaNode) {
+ schemaNode = (DataSchemaNode) schemaNodeContext;
+
+ final String docRootElm = doc.getDocumentElement().getLocalName();
+ final XMLNamespace docRootNamespace = XMLNamespace.of(doc.getDocumentElement().getNamespaceURI());
+
+ if (isPost()) {
+ final var context = pathContext.getSchemaContext();
+ final var it = context.findModuleStatements(docRootNamespace).iterator();
+ checkState(it.hasNext(), "Failed to find module for %s", docRootNamespace);
+ final var qname = QName.create(it.next().localQNameModule(), docRootElm);
+
+ final var nodeAndStack = DataSchemaContextTree.from(context)
+ .enterPath(pathContext.getInstanceIdentifier()).orElseThrow();
+
+ final var stack = nodeAndStack.stack();
+ var current = nodeAndStack.node();
+ do {
+ final var next = current.enterChild(stack, qname);
+ checkState(next != null, "Child \"%s\" was not found in parent schema node \"%s\"", qname,
+ schemaNode);
+ iiToDataList.add(next.getIdentifier());
+ schemaNode = next.getDataSchemaNode();
+ current = next;
+ } while (current.isMixin());
+
+ // We need to unwind the last identifier if it a NodeIdentifierWithPredicates, as it does not have
+ // any predicates at all. The real identifier is then added below
+ if (stack.currentStatement() instanceof ListEffectiveStatement) {
+ iiToDataList.remove(iiToDataList.size() - 1);
+ }
+
+ inference = stack.toInference();
+
+ } else {
+ // PUT
+ final QName scQName = schemaNode.getQName();
+ checkState(docRootElm.equals(scQName.getLocalName()) && docRootNamespace.equals(scQName.getNamespace()),
+ "Not correct message root element \"%s\", should be \"%s\"", docRootElm, scQName);
+ inference = pathContext.inference();
+ }
+ } else {
+ throw new IllegalStateException("Unknown SchemaNode");
+ }
+
+
+ NormalizedNode parsed;
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+
+ if (schemaNode instanceof ContainerLike || schemaNode instanceof ListSchemaNode
+ || schemaNode instanceof LeafSchemaNode) {
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, inference);
+ xmlParser.traverse(new DOMSource(doc.getDocumentElement()));
+ parsed = resultHolder.getResult();
+
+ // When parsing an XML source with a list root node
+ // the new XML parser always returns a MapNode with one MapEntryNode inside.
+ // However, the old XML parser returned a MapEntryNode directly in this place.
+ // Therefore we now have to extract the MapEntryNode from the parsed MapNode.
+ if (parsed instanceof MapNode) {
+ final MapNode mapNode = (MapNode) parsed;
+ // extracting the MapEntryNode
+ parsed = mapNode.body().iterator().next();
+ }
+
+ if (schemaNode instanceof ListSchemaNode && isPost()) {
+ iiToDataList.add(parsed.getIdentifier());
+ }
+ } else {
+ LOG.warn("Unknown schema node extension {} was not parsed", schemaNode.getClass());
+ parsed = null;
+ }
+
+ return new NormalizedNodeContext(pathContext.withConcatenatedArgs(iiToDataList), parsed);
+ }
+}
+
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlToPatchBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlToPatchBodyReader.java
new file mode 100644
index 0000000..9cc4766
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/XmlToPatchBodyReader.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import static com.google.common.base.Verify.verify;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.dom.DOMSource;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchEditOperation;
+import org.opendaylight.restconf.common.patch.PatchEntity;
+import org.opendaylight.restconf.common.util.RestUtil;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * Yang PATCH Reader for XML.
+ *
+ * @deprecated This class will be replaced by XmlToPatchBodyReader from restconf-nb-rfc8040
+ */
+@Deprecated
+@Provider
+@Consumes({Draft02.MediaTypes.PATCH + RestconfService.XML})
+public class XmlToPatchBodyReader extends AbstractIdentifierAwareJaxRsProvider implements
+ MessageBodyReader<PatchContext> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(XmlToPatchBodyReader.class);
+
+ public XmlToPatchBodyReader(final ControllerContext controllerContext) {
+ super(controllerContext);
+ }
+
+ @Override
+ public boolean isReadable(final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
+ return true;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public PatchContext readFrom(final Class<PatchContext> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream)
+ throws WebApplicationException {
+
+ try {
+ final InstanceIdentifierContext path = getInstanceIdentifierContext();
+ final Optional<InputStream> nonEmptyInputStreamOptional = RestUtil.isInputStreamEmpty(entityStream);
+ if (nonEmptyInputStreamOptional.isEmpty()) {
+ // represent empty nopayload input
+ return new PatchContext(path, null, null);
+ }
+
+ final Document doc = UntrustedXML.newDocumentBuilder().parse(nonEmptyInputStreamOptional.get());
+ return parse(path, doc);
+ } catch (final RestconfDocumentedException e) {
+ throw e;
+ } catch (final Exception e) {
+ LOG.debug("Error parsing xml input", e);
+ RestconfDocumentedException.throwIfYangError(e);
+ throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE, e);
+ }
+ }
+
+ private static PatchContext parse(final InstanceIdentifierContext pathContext, final Document doc)
+ throws XMLStreamException, IOException, ParserConfigurationException, SAXException, URISyntaxException {
+ final List<PatchEntity> resultCollection = new ArrayList<>();
+ final String patchId = doc.getElementsByTagName("patch-id").item(0).getFirstChild().getNodeValue();
+ final NodeList editNodes = doc.getElementsByTagName("edit");
+
+ for (int i = 0; i < editNodes.getLength(); i++) {
+ DataSchemaNode schemaNode = (DataSchemaNode) pathContext.getSchemaNode();
+ final Element element = (Element) editNodes.item(i);
+ final String operation = element.getElementsByTagName("operation").item(0).getFirstChild().getNodeValue();
+ final PatchEditOperation oper = PatchEditOperation.valueOf(operation.toUpperCase(Locale.ROOT));
+
+ final String editId = element.getElementsByTagName("edit-id").item(0).getFirstChild().getNodeValue();
+ final String target = element.getElementsByTagName("target").item(0).getFirstChild().getNodeValue();
+ final List<Element> values = readValueNodes(element, oper);
+ final Element firstValueElement = values != null ? values.get(0) : null;
+
+ // get namespace according to schema node from path context or value
+ final String namespace = firstValueElement == null
+ ? schemaNode.getQName().getNamespace().toString() : firstValueElement.getNamespaceURI();
+
+ // find module according to namespace
+ final Module module = pathContext.getSchemaContext().findModules(XMLNamespace.of(namespace)).iterator()
+ .next();
+
+ // initialize codec + set default prefix derived from module name
+ final StringModuleInstanceIdentifierCodec codec = new StringModuleInstanceIdentifierCodec(
+ pathContext.getSchemaContext(), module.getName());
+
+ // find complete path to target and target schema node
+ // target can be also empty (only slash)
+ YangInstanceIdentifier targetII;
+ final SchemaNode targetNode;
+ final Inference inference;
+ if (target.equals("/")) {
+ targetII = pathContext.getInstanceIdentifier();
+ targetNode = pathContext.getSchemaContext();
+ inference = pathContext.inference();
+ } else {
+ targetII = codec.deserialize(codec.serialize(pathContext.getInstanceIdentifier())
+ .concat(prepareNonCondXpath(schemaNode, target.replaceFirst("/", ""), firstValueElement,
+ namespace,
+ module.getQNameModule().getRevision().map(Revision::toString).orElse(null))));
+ // move schema node
+ final var result = codec.getDataContextTree().enterPath(targetII).orElseThrow();
+ schemaNode = result.node().getDataSchemaNode();
+
+ final var stack = result.stack();
+ inference = stack.toInference();
+
+ stack.exit();
+ final EffectiveStatement<?, ?> parentStmt = stack.currentStatement();
+ verify(parentStmt instanceof SchemaNode, "Unexpected parent %s", parentStmt);
+ targetNode = (SchemaNode) parentStmt;
+ }
+
+ if (targetNode == null) {
+ LOG.debug("Target node {} not found in path {} ", target, pathContext.getSchemaNode());
+ throw new RestconfDocumentedException("Error parsing input", ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE);
+ }
+
+ if (oper.isWithValue()) {
+ final NormalizedNode parsed;
+ if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode) {
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, inference);
+ xmlParser.traverse(new DOMSource(firstValueElement));
+ parsed = resultHolder.getResult();
+ } else {
+ parsed = null;
+ }
+
+ // for lists allow to manipulate with list items through their parent
+ if (targetII.getLastPathArgument() instanceof NodeIdentifierWithPredicates) {
+ targetII = targetII.getParent();
+ }
+
+ resultCollection.add(new PatchEntity(editId, oper, targetII, parsed));
+ } else {
+ resultCollection.add(new PatchEntity(editId, oper, targetII));
+ }
+ }
+
+ return new PatchContext(pathContext, ImmutableList.copyOf(resultCollection), patchId);
+ }
+
+ /**
+ * Read value nodes.
+ *
+ * @param element Element of current edit operation
+ * @param operation Name of current operation
+ * @return List of value elements
+ */
+ private static List<Element> readValueNodes(final @NonNull Element element,
+ final @NonNull PatchEditOperation operation) {
+ final Node valueNode = element.getElementsByTagName("value").item(0);
+
+ if (operation.isWithValue() && valueNode == null) {
+ throw new RestconfDocumentedException("Error parsing input",
+ ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ }
+
+ if (!operation.isWithValue() && valueNode != null) {
+ throw new RestconfDocumentedException("Error parsing input",
+ ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ }
+
+ if (valueNode == null) {
+ return null;
+ }
+
+ final List<Element> result = new ArrayList<>();
+ final NodeList childNodes = valueNode.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ if (childNodes.item(i) instanceof Element) {
+ result.add((Element) childNodes.item(i));
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Prepare non-conditional XPath suitable for deserialization with {@link StringModuleInstanceIdentifierCodec}.
+ *
+ * @param schemaNode Top schema node
+ * @param target Edit operation target
+ * @param value Element with value
+ * @param namespace Module namespace
+ * @param revision Module revision
+ * @return Non-conditional XPath
+ */
+ private static String prepareNonCondXpath(final @NonNull DataSchemaNode schemaNode, final @NonNull String target,
+ final @NonNull Element value, final @NonNull String namespace, final @NonNull String revision) {
+ final Iterator<String> args = Splitter.on("/").split(target.substring(target.indexOf(':') + 1)).iterator();
+
+ final StringBuilder nonCondXpath = new StringBuilder();
+ SchemaNode childNode = schemaNode;
+
+ while (args.hasNext()) {
+ final String s = args.next();
+ nonCondXpath.append('/').append(s);
+ childNode = ((DataNodeContainer) childNode).getDataChildByName(QName.create(namespace, revision, s));
+
+ if (childNode instanceof ListSchemaNode && args.hasNext()) {
+ appendKeys(nonCondXpath, ((ListSchemaNode) childNode).getKeyDefinition().iterator(), args);
+ }
+ }
+
+ if (childNode instanceof ListSchemaNode && value != null) {
+ final Iterator<String> keyValues = readKeyValues(value,
+ ((ListSchemaNode) childNode).getKeyDefinition().iterator());
+ appendKeys(nonCondXpath, ((ListSchemaNode) childNode).getKeyDefinition().iterator(), keyValues);
+ }
+
+ return nonCondXpath.toString();
+ }
+
+ /**
+ * Read value for every list key.
+ *
+ * @param value Value element
+ * @param keys Iterator of list keys names
+ * @return Iterator of list keys values
+ */
+ private static Iterator<String> readKeyValues(final @NonNull Element value, final @NonNull Iterator<QName> keys) {
+ final List<String> result = new ArrayList<>();
+
+ while (keys.hasNext()) {
+ result.add(value.getElementsByTagName(keys.next().getLocalName()).item(0).getFirstChild().getNodeValue());
+ }
+
+ return result.iterator();
+ }
+
+ /**
+ * Append key name - key value pairs for every list key to {@code nonCondXpath}.
+ *
+ * @param nonCondXpath Builder for creating non-conditional XPath
+ * @param keyNames Iterator of list keys names
+ * @param keyValues Iterator of list keys values
+ */
+ private static void appendKeys(final @NonNull StringBuilder nonCondXpath, final @NonNull Iterator<QName> keyNames,
+ final @NonNull Iterator<String> keyValues) {
+ while (keyNames.hasNext()) {
+ nonCondXpath.append("[").append(keyNames.next().getLocalName()).append("='").append(keyValues.next())
+ .append("']");
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/package-info.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/package-info.java
new file mode 100644
index 0000000..07eb8e2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/rest/impl/package-info.java
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl; \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/api/JSONRestconfService.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/api/JSONRestconfService.java
new file mode 100644
index 0000000..5e3426c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/api/JSONRestconfService.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.api;
+
+import java.util.Optional;
+import javax.ws.rs.core.MultivaluedMap;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.common.OperationFailedException;
+
+/**
+ * Provides restconf CRUD operations via code with input/output data in JSON format.
+ *
+ * @author Thomas Pantelis.
+ */
+public interface JSONRestconfService {
+ /**
+ * The data tree root path.
+ */
+ String ROOT_PATH = null;
+
+ /**
+ * Issues a restconf PUT request to the configuration data store.
+ *
+ * @param uriPath the yang instance identifier path, eg "opendaylight-inventory:nodes/node/device-id".
+ * To specify the root, use {@link ROOT_PATH}.
+ * @param payload the payload data in JSON format.
+ * @throws OperationFailedException if the request fails.
+ */
+ void put(String uriPath, @NonNull String payload) throws OperationFailedException;
+
+ /**
+ * Issues a restconf POST request to the configuration data store.
+ *
+ * @param uriPath the yang instance identifier path, eg "opendaylight-inventory:nodes/node/device-id".
+ * To specify the root, use {@link ROOT_PATH}.
+ * @param payload the payload data in JSON format.
+ * @throws OperationFailedException if the request fails.
+ */
+ void post(String uriPath, @NonNull String payload) throws OperationFailedException;
+
+ /**
+ * Issues a restconf DELETE request to the configuration data store.
+ *
+ * @param uriPath the yang instance identifier path, eg "opendaylight-inventory:nodes/node/device-id".
+ * To specify the root, use {@link ROOT_PATH}.
+ * @throws OperationFailedException if the request fails.
+ */
+ void delete(String uriPath) throws OperationFailedException;
+
+ /**
+ * Issues a restconf GET request to the given data store.
+ *
+ * @param uriPath the yang instance identifier path, eg "opendaylight-inventory:nodes/node/device-id".
+ * To specify the root, use {@link ROOT_PATH}.
+ * @param datastoreType the data store type to read from.
+ * @return an Optional containing the data in JSON format if present.
+ * @throws OperationFailedException if the request fails.
+ */
+ Optional<String> get(String uriPath, LogicalDatastoreType datastoreType)
+ throws OperationFailedException;
+
+ /**
+ * Invokes a yang-defined RPC.
+ *
+ * @param uriPath the path representing the RPC to invoke, eg "toaster:make-toast".
+ * @param input the input in JSON format if the RPC takes input.
+ * @return an Optional containing the output in JSON format if the RPC returns output.
+ * @throws OperationFailedException if the request fails.
+ */
+ Optional<String> invokeRpc(@NonNull String uriPath, Optional<String> input) throws OperationFailedException;
+
+ /**
+ * Issues a restconf PATCH request to the configuration data store.
+ *
+ * @param uriPath the yang instance identifier path, eg "opendaylight-inventory:nodes/node/device-id".
+ * To specify the root, use {@link ROOT_PATH}.
+ * @param payload the payload data in JSON format.
+ * @return an Optional containing the patch response data in JSON format.
+ * @throws OperationFailedException if the request fails.
+ */
+ Optional<String> patch(@NonNull String uriPath, @NonNull String payload) throws OperationFailedException;
+
+ /**
+ * Subscribe to a stream.
+ * @param identifier the identifier of the stream, e.g., "data-change-event-subscription/neutron:neutron/...
+ * ...neutron:ports/datastore=OPERATIONAL/scope=SUBTREE".
+ * @param params HTTP query parameters or null.
+ * @return On optional containing the JSON response.
+ * @throws OperationFailedException if the requests fails.
+ */
+ Optional<String> subscribeToStream(@NonNull String identifier, MultivaluedMap<String, String> params)
+ throws OperationFailedException;
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/api/RestConfConfig.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/api/RestConfConfig.java
new file mode 100644
index 0000000..169a69d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/api/RestConfConfig.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.api;
+
+import java.net.InetAddress;
+
+/**
+ * Configuration for the RESTCONF server.
+ *
+ * @author Michael Vorburger.ch
+ */
+public interface RestConfConfig {
+
+ /**
+ * IP interface which the WebSocket server will listen on.
+ */
+ default InetAddress webSocketAddress() {
+ return InetAddress.getLoopbackAddress();
+ }
+
+ /**
+ * TCP port which the WebSocket server will listen on.
+ */
+ int webSocketPort();
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BatchedExistenceCheck.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BatchedExistenceCheck.java
new file mode 100644
index 0000000..4efc6a8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BatchedExistenceCheck.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Collection;
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadOperations;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+final class BatchedExistenceCheck {
+ private static final AtomicIntegerFieldUpdater<BatchedExistenceCheck> UPDATER =
+ AtomicIntegerFieldUpdater.newUpdater(BatchedExistenceCheck.class, "outstanding");
+
+ private final SettableFuture<Entry<YangInstanceIdentifier, ReadFailedException>> future = SettableFuture.create();
+
+ @SuppressWarnings("unused")
+ private volatile int outstanding;
+
+ private BatchedExistenceCheck(final int total) {
+ this.outstanding = total;
+ }
+
+ static BatchedExistenceCheck start(final DOMDataTreeReadOperations readTx,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier parentPath,
+ final Collection<? extends NormalizedNode> children) {
+ final BatchedExistenceCheck ret = new BatchedExistenceCheck(children.size());
+ for (NormalizedNode child : children) {
+ final YangInstanceIdentifier path = parentPath.node(child.getIdentifier());
+ readTx.exists(datastore, path).addCallback(new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(final Boolean result) {
+ ret.complete(path, result);
+ }
+
+ @Override
+ @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
+ public void onFailure(final Throwable throwable) {
+ final Exception e;
+ if (throwable instanceof Exception) {
+ e = (Exception) throwable;
+ } else {
+ e = new ExecutionException(throwable);
+ }
+
+ ret.complete(path, ReadFailedException.MAPPER.apply(e));
+ }
+ }, MoreExecutors.directExecutor());
+ }
+
+ return ret;
+ }
+
+ Entry<YangInstanceIdentifier, ReadFailedException> getFailure() throws InterruptedException {
+ try {
+ return future.get();
+ } catch (ExecutionException e) {
+ // This should never happen
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private void complete(final YangInstanceIdentifier childPath, final boolean present) {
+ final int count = UPDATER.decrementAndGet(this);
+ if (present) {
+ future.set(new SimpleImmutableEntry<>(childPath, null));
+ } else if (count == 0) {
+ future.set(null);
+ }
+ }
+
+ private void complete(final YangInstanceIdentifier childPath, final ReadFailedException cause) {
+ UPDATER.decrementAndGet(this);
+ future.set(new SimpleImmutableEntry<>(childPath, cause));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/Bierman02RestConfWiring.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/Bierman02RestConfWiring.java
new file mode 100644
index 0000000..18d19e4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/Bierman02RestConfWiring.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.servlet.ServletException;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMMountPointService;
+import org.opendaylight.mdsal.dom.api.DOMNotificationService;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.netconf.sal.rest.impl.RestconfApplication;
+import org.opendaylight.netconf.sal.restconf.api.RestConfConfig;
+import org.opendaylight.netconf.sal.restconf.web.WebInitializer;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+import org.opendaylight.yangtools.yang.common.Uint16;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Standalone wiring for RESTCONF.
+ *
+ * <p>ACK: Some lines here were originally inspired by the RestConfWiring class in
+ * opendaylight-simple which in turn was inspired by the CommunityRestConf class
+ * from lighty.io. The differences include (1) that this class is "pure Java"
+ * without depending on any binding framework utility classes; (2) we do not mix
+ * bierman02 and rfc8040 for proper modularity; (3) we simply use {@literal @}Inject
+ * instead of manual object wiring, where possible.
+ *
+ * @author Michael Vorburger.ch (see ACK note for history)
+ */
+@SuppressWarnings("deprecation")
+// NOT @Singleton, to avoid that the blueprint-maven-plugin generates <bean>, which we don't want for this
+public class Bierman02RestConfWiring {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Bierman02RestConfWiring.class);
+
+ private final RestconfProviderImpl webSocketServer;
+
+ @Inject
+ // The point of all the arguments here is simply to make your chosen Dependency Injection (DI) framework init. them
+ public Bierman02RestConfWiring(final RestConfConfig config,
+ final DOMSchemaService domSchemaService, final DOMMountPointService domMountPointService,
+ final DOMRpcService domRpcService, final DOMDataBroker domDataBroker,
+ final DOMNotificationService domNotificationService, final ControllerContext controllerContext,
+ final RestconfApplication application, final BrokerFacade broker, final RestconfImpl restconf,
+ final StatisticsRestconfServiceWrapper stats, final JSONRestconfServiceImpl jsonRestconfServiceImpl,
+ final WebInitializer webInitializer) {
+
+ // WebSocket
+ LOG.info("webSocketAddress = {}, webSocketPort = {}", config.webSocketAddress(), config.webSocketPort());
+ IpAddress wsIpAddress = IpAddressBuilder.getDefaultInstance(config.webSocketAddress().getHostAddress());
+ this.webSocketServer = new RestconfProviderImpl(stats, wsIpAddress,
+ new PortNumber(Uint16.valueOf(config.webSocketPort())));
+ }
+
+ @PostConstruct
+ public void start() throws ServletException {
+ this.webSocketServer.start();
+ }
+
+ @PreDestroy
+ public void stop() {
+ this.webSocketServer.close();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java
new file mode 100644
index 0000000..ca867cb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java
@@ -0,0 +1,1277 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION;
+import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.OPERATIONAL;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.core.Response.Status;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadOperations;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMNotificationListener;
+import org.opendaylight.mdsal.dom.api.DOMNotificationService;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchEditOperation;
+import org.opendaylight.restconf.common.patch.PatchEntity;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.restconf.common.patch.PatchStatusEntity;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.CreateDataChangeEventSubscriptionInput1.Scope;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UserLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UserMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class BrokerFacade implements Closeable {
+ private static final Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
+
+ private final ThreadLocal<Boolean> isMounted = new ThreadLocal<>();
+ private final DOMNotificationService domNotification;
+ private final ControllerContext controllerContext;
+ private final DOMDataBroker domDataBroker;
+
+ private volatile DOMRpcService rpcService;
+
+ @Inject
+ public BrokerFacade(final DOMRpcService rpcService, final DOMDataBroker domDataBroker,
+ final DOMNotificationService domNotification, final ControllerContext controllerContext) {
+ this.rpcService = requireNonNull(rpcService);
+ this.domDataBroker = requireNonNull(domDataBroker);
+ this.domNotification = requireNonNull(domNotification);
+ this.controllerContext = requireNonNull(controllerContext);
+ }
+
+ /**
+ * Factory method.
+ *
+ * @deprecated Just use
+ * {@link #BrokerFacade(DOMRpcService, DOMDataBroker, DOMNotificationService, ControllerContext)}
+ * constructor instead.
+ */
+ @Deprecated
+ public static BrokerFacade newInstance(final DOMRpcService rpcService, final DOMDataBroker domDataBroker,
+ final DOMNotificationService domNotification, final ControllerContext controllerContext) {
+ return new BrokerFacade(rpcService, domDataBroker, domNotification, controllerContext);
+ }
+
+ @Override
+ @PreDestroy
+ public void close() {
+ }
+
+ /**
+ * Read config data by path.
+ *
+ * @param path
+ * path of data
+ * @return read date
+ */
+ public NormalizedNode readConfigurationData(final YangInstanceIdentifier path) {
+ return readConfigurationData(path, null);
+ }
+
+ /**
+ * Read config data by path.
+ *
+ * @param path
+ * path of data
+ * @param withDefa
+ * value of with-defaults parameter
+ * @return read date
+ */
+ public NormalizedNode readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
+ try (DOMDataTreeReadTransaction tx = domDataBroker.newReadOnlyTransaction()) {
+ return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
+ }
+ }
+
+ /**
+ * Read config data from mount point by path.
+ *
+ * @param mountPoint
+ * mount point for reading data
+ * @param path
+ * path of data
+ * @return read data
+ */
+ public NormalizedNode readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
+ return readConfigurationData(mountPoint, path, null);
+ }
+
+ /**
+ * Read config data from mount point by path.
+ *
+ * @param mountPoint
+ * mount point for reading data
+ * @param path
+ * path of data
+ * @param withDefa
+ * value of with-defaults parameter
+ * @return read data
+ */
+ public NormalizedNode readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
+ final String withDefa) {
+ final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
+ if (domDataBrokerService.isPresent()) {
+ try (DOMDataTreeReadTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
+ return readDataViaTransaction(tx, CONFIGURATION, path, withDefa);
+ }
+ }
+ throw dataBrokerUnavailable(path);
+ }
+
+ /**
+ * Read operational data by path.
+ *
+ * @param path
+ * path of data
+ * @return read data
+ */
+ public NormalizedNode readOperationalData(final YangInstanceIdentifier path) {
+ try (DOMDataTreeReadTransaction tx = domDataBroker.newReadOnlyTransaction()) {
+ return readDataViaTransaction(tx, OPERATIONAL, path);
+ }
+ }
+
+ /**
+ * Read operational data from mount point by path.
+ *
+ * @param mountPoint
+ * mount point for reading data
+ * @param path
+ * path of data
+ * @return read data
+ */
+ public NormalizedNode readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
+ final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
+ if (domDataBrokerService.isPresent()) {
+ try (DOMDataTreeReadTransaction tx = domDataBrokerService.get().newReadOnlyTransaction()) {
+ return readDataViaTransaction(tx, OPERATIONAL, path);
+ }
+ }
+ throw dataBrokerUnavailable(path);
+ }
+
+ /**
+ * <b>PUT configuration data</b>
+ *
+ * <p>
+ * Prepare result(status) for PUT operation and PUT data via transaction.
+ * Return wrapped status and future from PUT.
+ *
+ * @param globalSchema
+ * used by merge parents (if contains list)
+ * @param path
+ * path of node
+ * @param payload
+ * input data
+ * @param point
+ * point
+ * @param insert
+ * insert
+ * @return wrapper of status and future of PUT
+ */
+ public PutResult commitConfigurationDataPut(final EffectiveModelContext globalSchema,
+ final YangInstanceIdentifier path, final NormalizedNode payload, final String insert, final String point) {
+ requireNonNull(globalSchema);
+ requireNonNull(path);
+ requireNonNull(payload);
+
+ isMounted.set(false);
+ final DOMDataTreeReadWriteTransaction newReadWriteTransaction = domDataBroker.newReadWriteTransaction();
+ final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
+ : Status.CREATED;
+ final FluentFuture<? extends CommitInfo> future = putDataViaTransaction(
+ newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema, insert, point);
+ isMounted.remove();
+ return new PutResult(status, future);
+ }
+
+ /**
+ * <b>PUT configuration data (Mount point)</b>
+ *
+ * <p>
+ * Prepare result(status) for PUT operation and PUT data via transaction.
+ * Return wrapped status and future from PUT.
+ *
+ * @param mountPoint
+ * mount point for getting transaction for operation and schema
+ * context for merging parents(if contains list)
+ * @param path
+ * path of node
+ * @param payload
+ * input data
+ * @param point
+ * point
+ * @param insert
+ * insert
+ * @return wrapper of status and future of PUT
+ */
+ public PutResult commitMountPointDataPut(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
+ final NormalizedNode payload, final String insert, final String point) {
+ requireNonNull(mountPoint);
+ requireNonNull(path);
+ requireNonNull(payload);
+
+ isMounted.set(true);
+ final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
+ if (domDataBrokerService.isPresent()) {
+ final DOMDataTreeReadWriteTransaction newReadWriteTransaction =
+ domDataBrokerService.get().newReadWriteTransaction();
+ final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
+ ? Status.OK : Status.CREATED;
+ final FluentFuture<? extends CommitInfo> future = putDataViaTransaction(
+ newReadWriteTransaction, CONFIGURATION, path, payload, modelContext(mountPoint), insert, point);
+ isMounted.remove();
+ return new PutResult(status, future);
+ }
+ isMounted.remove();
+ throw dataBrokerUnavailable(path);
+ }
+
+ public PatchStatusContext patchConfigurationDataWithinTransaction(final PatchContext patchContext)
+ throws Exception {
+ final DOMMountPoint mountPoint = patchContext.getInstanceIdentifierContext().getMountPoint();
+
+ // get new transaction and schema context on server or on mounted device
+ final EffectiveModelContext schemaContext;
+ final DOMDataTreeReadWriteTransaction patchTransaction;
+ if (mountPoint == null) {
+ schemaContext = patchContext.getInstanceIdentifierContext().getSchemaContext();
+ patchTransaction = domDataBroker.newReadWriteTransaction();
+ } else {
+ schemaContext = modelContext(mountPoint);
+
+ final Optional<DOMDataBroker> optional = mountPoint.getService(DOMDataBroker.class);
+
+ if (optional.isPresent()) {
+ patchTransaction = optional.get().newReadWriteTransaction();
+ } else {
+ // if mount point does not have broker it is not possible to continue and global error is reported
+ LOG.error("Http Patch {} has failed - device {} does not support broker service",
+ patchContext.getPatchId(), mountPoint.getIdentifier());
+ return new PatchStatusContext(
+ patchContext.getPatchId(),
+ null,
+ false,
+ ImmutableList.of(new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED,
+ "DOM data broker service isn't available for mount point " + mountPoint.getIdentifier()))
+ );
+ }
+ }
+
+ final List<PatchStatusEntity> editCollection = new ArrayList<>();
+ List<RestconfError> editErrors;
+ boolean withoutError = true;
+
+ for (final PatchEntity patchEntity : patchContext.getData()) {
+ final PatchEditOperation operation = patchEntity.getOperation();
+ switch (operation) {
+ case CREATE:
+ if (withoutError) {
+ try {
+ postDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
+ patchEntity.getNode(), schemaContext);
+ editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
+ } catch (final RestconfDocumentedException e) {
+ LOG.error("Error call http Patch operation {} on target {}",
+ operation,
+ patchEntity.getTargetNode().toString());
+
+ editErrors = new ArrayList<>();
+ editErrors.addAll(e.getErrors());
+ editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
+ withoutError = false;
+ }
+ }
+ break;
+ case REPLACE:
+ if (withoutError) {
+ try {
+ putDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
+ .getTargetNode(), patchEntity.getNode(), schemaContext);
+ editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
+ } catch (final RestconfDocumentedException e) {
+ LOG.error("Error call http Patch operation {} on target {}",
+ operation,
+ patchEntity.getTargetNode().toString());
+
+ editErrors = new ArrayList<>();
+ editErrors.addAll(e.getErrors());
+ editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
+ withoutError = false;
+ }
+ }
+ break;
+ case DELETE:
+ case REMOVE:
+ if (withoutError) {
+ try {
+ deleteDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity
+ .getTargetNode());
+ editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
+ } catch (final RestconfDocumentedException e) {
+ LOG.error("Error call http Patch operation {} on target {}",
+ operation,
+ patchEntity.getTargetNode().toString());
+
+ editErrors = new ArrayList<>();
+ editErrors.addAll(e.getErrors());
+ editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
+ withoutError = false;
+ }
+ }
+ break;
+ case MERGE:
+ if (withoutError) {
+ try {
+ mergeDataWithinTransaction(patchTransaction, CONFIGURATION, patchEntity.getTargetNode(),
+ patchEntity.getNode(), schemaContext);
+ editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
+ } catch (final RestconfDocumentedException e) {
+ LOG.error("Error call http Patch operation {} on target {}",
+ operation,
+ patchEntity.getTargetNode().toString());
+
+ editErrors = new ArrayList<>();
+ editErrors.addAll(e.getErrors());
+ editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), false, editErrors));
+ withoutError = false;
+ }
+ }
+ break;
+ default:
+ LOG.error("Unsupported http Patch operation {} on target {}",
+ operation,
+ patchEntity.getTargetNode().toString());
+ break;
+ }
+ }
+
+ // if errors then cancel transaction and return error status
+ if (!withoutError) {
+ patchTransaction.cancel();
+ return new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
+ }
+
+ // if no errors commit transaction
+ final CountDownLatch waiter = new CountDownLatch(1);
+ final FluentFuture<? extends CommitInfo> future = patchTransaction.commit();
+ final PatchStatusContextHelper status = new PatchStatusContextHelper();
+
+ future.addCallback(new FutureCallback<CommitInfo>() {
+ @Override
+ public void onSuccess(final CommitInfo result) {
+ status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
+ true, null));
+ waiter.countDown();
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ // if commit failed it is global error
+ LOG.error("Http Patch {} transaction commit has failed", patchContext.getPatchId());
+ status.setStatus(new PatchStatusContext(patchContext.getPatchId(), ImmutableList.copyOf(editCollection),
+ false, ImmutableList.of(
+ new RestconfError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, throwable.getMessage()))));
+ waiter.countDown();
+ }
+ }, MoreExecutors.directExecutor());
+
+ waiter.await();
+ return status.getStatus();
+ }
+
+ // POST configuration
+ public FluentFuture<? extends CommitInfo> commitConfigurationDataPost(
+ final EffectiveModelContext globalSchema, final YangInstanceIdentifier path,
+ final NormalizedNode payload, final String insert, final String point) {
+ isMounted.set(false);
+ FluentFuture<? extends CommitInfo> future =
+ postDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload,
+ globalSchema, insert, point);
+ isMounted.remove();
+ return future;
+ }
+
+ public FluentFuture<? extends CommitInfo> commitConfigurationDataPost(
+ final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode payload,
+ final String insert, final String point) {
+ isMounted.set(true);
+ final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
+ if (domDataBrokerService.isPresent()) {
+ FluentFuture<? extends CommitInfo> future =
+ postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
+ payload, modelContext(mountPoint), insert, point);
+ isMounted.remove();
+ return future;
+ }
+ isMounted.remove();
+ throw dataBrokerUnavailable(path);
+ }
+
+ // DELETE configuration
+ public FluentFuture<? extends CommitInfo> commitConfigurationDataDelete(final YangInstanceIdentifier path) {
+ return deleteDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
+ }
+
+ public FluentFuture<? extends CommitInfo> commitConfigurationDataDelete(
+ final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
+ final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
+ if (domDataBrokerService.isPresent()) {
+ return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
+ }
+ throw dataBrokerUnavailable(path);
+ }
+
+ // RPC
+ public ListenableFuture<? extends DOMRpcResult> invokeRpc(final @NonNull QName type,
+ final @NonNull NormalizedNode input) {
+ if (rpcService == null) {
+ throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
+ }
+ LOG.trace("Invoke RPC {} with input: {}", type, input);
+ return rpcService.invokeRpc(type, input);
+ }
+
+ public void registerToListenDataChanges(final LogicalDatastoreType datastore, final Scope scope,
+ final ListenerAdapter listener) {
+ if (listener.isListening()) {
+ return;
+ }
+
+ final YangInstanceIdentifier path = listener.getPath();
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(DOMDataTreeChangeService.class);
+ if (changeService == null) {
+ throw new UnsupportedOperationException("DOMDataBroker does not support the DOMDataTreeChangeService"
+ + domDataBroker);
+ }
+ DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(datastore, path);
+ ListenerRegistration<ListenerAdapter> registration =
+ changeService.registerDataTreeChangeListener(root, listener);
+ listener.setRegistration(registration);
+ }
+
+ private NormalizedNode readDataViaTransaction(final DOMDataTreeReadOperations transaction,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
+ return readDataViaTransaction(transaction, datastore, path, null);
+ }
+
+ private NormalizedNode readDataViaTransaction(final DOMDataTreeReadOperations transaction,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
+ LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
+
+ try {
+ final Optional<NormalizedNode> optional = transaction.read(datastore, path).get();
+ return optional.map(normalizedNode -> withDefa == null ? normalizedNode :
+ prepareDataByParamWithDef(normalizedNode, path, withDefa)).orElse(null);
+ } catch (InterruptedException e) {
+ LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
+ throw new RestconfDocumentedException("Error reading data.", e);
+ } catch (ExecutionException e) {
+ LOG.warn("Error reading {} from datastore {}", path, datastore.name(), e);
+ throw RestconfDocumentedException.decodeAndThrow("Error reading data.", Throwables.getCauseAs(e,
+ ReadFailedException.class));
+ }
+ }
+
+ private NormalizedNode prepareDataByParamWithDef(final NormalizedNode result,
+ final YangInstanceIdentifier path, final String withDefa) {
+ boolean trim;
+ switch (withDefa) {
+ case "trim":
+ trim = true;
+ break;
+ case "explicit":
+ trim = false;
+ break;
+ default:
+ throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
+ }
+
+ final EffectiveModelContext ctx = controllerContext.getGlobalSchema();
+ final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
+ final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.findChild(path).orElseThrow().getDataSchemaNode();
+ if (result instanceof ContainerNode) {
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> builder =
+ SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
+ buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
+ return builder.build();
+ }
+
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
+ SchemaAwareBuilders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
+ buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
+ ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
+ return builder.build();
+ }
+
+ private void buildMapEntryBuilder(
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
+ final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
+ final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
+ for (final DataContainerChild child : result.body()) {
+ final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
+ final DataSchemaNode childSchema = baseSchemaCtxTree.findChild(path).orElseThrow().getDataSchemaNode();
+ if (child instanceof ContainerNode) {
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> childBuilder =
+ SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) childSchema);
+ buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
+ builder.withChild(childBuilder.build());
+ } else if (child instanceof MapNode) {
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> childBuilder =
+ SchemaAwareBuilders.mapBuilder((ListSchemaNode) childSchema);
+ buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
+ ((ListSchemaNode) childSchema).getKeyDefinition());
+ builder.withChild(childBuilder.build());
+ } else if (child instanceof LeafNode) {
+ final Object defaultVal = ((LeafSchemaNode) childSchema).getType().getDefaultValue().orElse(null);
+ final Object nodeVal = child.body();
+ final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) childSchema);
+ if (keys.contains(child.getIdentifier().getNodeType())) {
+ leafBuilder.withValue(child.body());
+ builder.withChild(leafBuilder.build());
+ } else {
+ if (trim) {
+ if (defaultVal == null || !defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(child.body());
+ builder.withChild(leafBuilder.build());
+ }
+ } else {
+ if (defaultVal != null && defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(child.body());
+ builder.withChild(leafBuilder.build());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void buildList(final CollectionNodeBuilder<MapEntryNode, SystemMapNode> builder, final MapNode result,
+ final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
+ final List<QName> keys) {
+ for (final MapEntryNode mapEntryNode : result.body()) {
+ final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
+ final DataSchemaNode childSchema = baseSchemaCtxTree.findChild(actualNode).orElseThrow()
+ .getDataSchemaNode();
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
+ SchemaAwareBuilders.mapEntryBuilder((ListSchemaNode) childSchema);
+ buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
+ builder.withChild(mapEntryBuilder.build());
+ }
+ }
+
+ private void buildCont(final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> builder,
+ final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
+ final YangInstanceIdentifier actualPath, final boolean trim) {
+ for (final DataContainerChild child : result.body()) {
+ final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
+ final DataSchemaNode childSchema = baseSchemaCtxTree.findChild(path).orElseThrow().getDataSchemaNode();
+ if (child instanceof ContainerNode) {
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> builderChild =
+ SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) childSchema);
+ buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
+ builder.withChild(builderChild.build());
+ } else if (child instanceof MapNode) {
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> childBuilder =
+ SchemaAwareBuilders.mapBuilder((ListSchemaNode) childSchema);
+ buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
+ ((ListSchemaNode) childSchema).getKeyDefinition());
+ builder.withChild(childBuilder.build());
+ } else if (child instanceof LeafNode) {
+ final Object defaultVal = ((LeafSchemaNode) childSchema).getType().getDefaultValue().orElse(null);
+ final Object nodeVal = child.body();
+ final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) childSchema);
+ if (trim) {
+ if (defaultVal == null || !defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(child.body());
+ builder.withChild(leafBuilder.build());
+ }
+ } else {
+ if (defaultVal != null && defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(child.body());
+ builder.withChild(leafBuilder.build());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * POST data and submit transaction {@link DOMDataReadWriteTransaction}.
+ */
+ private FluentFuture<? extends CommitInfo> postDataViaTransaction(
+ final DOMDataTreeReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext, final String insert, final String point) {
+ LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
+ postData(rwTransaction, datastore, path, payload, schemaContext, insert, point);
+ return rwTransaction.commit();
+ }
+
+ /**
+ * POST data and do NOT submit transaction {@link DOMDataReadWriteTransaction}.
+ */
+ private void postDataWithinTransaction(
+ final DOMDataTreeReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext) {
+ LOG.trace("POST {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
+ postData(rwTransaction, datastore, path, payload, schemaContext, null, null);
+ }
+
+ private void postData(final DOMDataTreeReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext, final String insert, final String point) {
+ if (insert == null) {
+ makeNormalPost(rwTransaction, datastore, path, payload, schemaContext);
+ return;
+ }
+
+ final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
+ checkItemDoesNotExists(rwTransaction, datastore, path);
+ switch (insert) {
+ case "first":
+ if (schemaNode instanceof ListSchemaNode) {
+ final UserMapNode readList =
+ (UserMapNode) this.readConfigurationData(path.getParent().getParent());
+ if (readList == null || readList.isEmpty()) {
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ } else {
+ rwTransaction.delete(datastore, path.getParent().getParent());
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readList,
+ schemaContext);
+ }
+ } else {
+ final UserLeafSetNode<?> readLeafList =
+ (UserLeafSetNode<?>) readConfigurationData(path.getParent());
+ if (readLeafList == null || readLeafList.isEmpty()) {
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ } else {
+ rwTransaction.delete(datastore, path.getParent());
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ makeNormalPost(rwTransaction, datastore, path.getParent().getParent(), readLeafList,
+ schemaContext);
+ }
+ }
+ break;
+ case "last":
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ break;
+ case "before":
+ if (schemaNode instanceof ListSchemaNode) {
+ final UserMapNode readList =
+ (UserMapNode) this.readConfigurationData(path.getParent().getParent());
+ if (readList == null || readList.isEmpty()) {
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ } else {
+ insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
+ readList,
+ true);
+ }
+ } else {
+ final UserLeafSetNode<?> readLeafList =
+ (UserLeafSetNode<?>) readConfigurationData(path.getParent());
+ if (readLeafList == null || readLeafList.isEmpty()) {
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ } else {
+ insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
+ readLeafList, true);
+ }
+ }
+ break;
+ case "after":
+ if (schemaNode instanceof ListSchemaNode) {
+ final UserMapNode readList =
+ (UserMapNode) this.readConfigurationData(path.getParent().getParent());
+ if (readList == null || readList.isEmpty()) {
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ } else {
+ insertWithPointListPost(rwTransaction, datastore, path, payload, schemaContext, point,
+ readList,
+ false);
+ }
+ } else {
+ final UserLeafSetNode<?> readLeafList =
+ (UserLeafSetNode<?>) readConfigurationData(path.getParent());
+ if (readLeafList == null || readLeafList.isEmpty()) {
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ } else {
+ insertWithPointLeafListPost(rwTransaction, datastore, path, payload, schemaContext, point,
+ readLeafList, false);
+ }
+ }
+ break;
+ default:
+ throw new RestconfDocumentedException(
+ "Used bad value of insert parameter. Possible values are first, last, before or after, "
+ + "but was: " + insert);
+ }
+ }
+
+ private void insertWithPointLeafListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext, final String point, final UserLeafSetNode<?> readLeafList,
+ final boolean before) {
+ rwTransaction.delete(datastore, path.getParent().getParent());
+ final InstanceIdentifierContext instanceIdentifier = controllerContext.toInstanceIdentifier(point);
+ int lastItemPosition = 0;
+ for (final LeafSetEntryNode<?> nodeChild : readLeafList.body()) {
+ if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
+ break;
+ }
+ lastItemPosition++;
+ }
+ if (!before) {
+ lastItemPosition++;
+ }
+ int lastInsertedPosition = 0;
+ final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
+ rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ for (final LeafSetEntryNode<?> nodeChild : readLeafList.body()) {
+ if (lastInsertedPosition == lastItemPosition) {
+ checkItemDoesNotExists(rwTransaction, datastore, path);
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ }
+ final YangInstanceIdentifier childPath = path.getParent().getParent().node(nodeChild.getIdentifier());
+ checkItemDoesNotExists(rwTransaction, datastore, childPath);
+ rwTransaction.put(datastore, childPath, nodeChild);
+ lastInsertedPosition++;
+ }
+ }
+
+ private void insertWithPointListPost(final DOMDataTreeReadWriteTransaction rwTransaction,
+ final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path, final NormalizedNode payload, final EffectiveModelContext schemaContext,
+ final String point, final MapNode readList, final boolean before) {
+ rwTransaction.delete(datastore, path.getParent().getParent());
+ final InstanceIdentifierContext instanceIdentifier = controllerContext.toInstanceIdentifier(point);
+ int lastItemPosition = 0;
+ for (final MapEntryNode mapEntryNode : readList.body()) {
+ if (mapEntryNode.getIdentifier()
+ .equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
+ break;
+ }
+ lastItemPosition++;
+ }
+ if (!before) {
+ lastItemPosition++;
+ }
+ int lastInsertedPosition = 0;
+ final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path.getParent().getParent());
+ rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ for (final MapEntryNode mapEntryNode : readList.body()) {
+ if (lastInsertedPosition == lastItemPosition) {
+ checkItemDoesNotExists(rwTransaction, datastore, path);
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ }
+ final YangInstanceIdentifier childPath = path.getParent().getParent().node(mapEntryNode.getIdentifier());
+ checkItemDoesNotExists(rwTransaction, datastore, childPath);
+ rwTransaction.put(datastore, childPath, mapEntryNode);
+ lastInsertedPosition++;
+ }
+ }
+
+ private static DataSchemaNode checkListAndOrderedType(final EffectiveModelContext ctx,
+ final YangInstanceIdentifier path) {
+ final YangInstanceIdentifier parent = path.getParent();
+ final DataSchemaContextNode<?> node = DataSchemaContextTree.from(ctx).findChild(parent).orElseThrow();
+ final DataSchemaNode dataSchemaNode = node.getDataSchemaNode();
+
+ if (dataSchemaNode instanceof ListSchemaNode) {
+ if (!((ListSchemaNode) dataSchemaNode).isUserOrdered()) {
+ throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list.");
+ }
+ return dataSchemaNode;
+ }
+ if (dataSchemaNode instanceof LeafListSchemaNode) {
+ if (!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) {
+ throw new RestconfDocumentedException(
+ "Insert parameter can be used only with ordered-by user leaf-list.");
+ }
+ return dataSchemaNode;
+ }
+ throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list");
+ }
+
+ private void makeNormalPost(final DOMDataTreeReadWriteTransaction rwTransaction,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext) {
+ final Collection<? extends NormalizedNode> children;
+ if (payload instanceof MapNode) {
+ children = ((MapNode) payload).body();
+ } else if (payload instanceof LeafSetNode) {
+ children = ((LeafSetNode<?>) payload).body();
+ } else {
+ simplePostPut(rwTransaction, datastore, path, payload, schemaContext);
+ return;
+ }
+
+ final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
+ if (children.isEmpty()) {
+ if (isMounted != null && !isMounted.get()) {
+
+ rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()),
+ emptySubtree);
+ ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
+ }
+ return;
+ }
+
+ // Kick off batch existence check first...
+ final BatchedExistenceCheck check = BatchedExistenceCheck.start(rwTransaction, datastore, path, children);
+
+ // ... now enqueue modifications. This relies on proper ordering of requests, i.e. these will not affect the
+ // result of the existence checks...
+ if (isMounted != null && !isMounted.get()) {
+
+ rwTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
+ }
+ for (final NormalizedNode child : children) {
+ // FIXME: we really want a create(YangInstanceIdentifier, NormalizedNode) method in the transaction,
+ // as that would allow us to skip the existence checks
+ rwTransaction.put(datastore, path.node(child.getIdentifier()), child);
+ }
+
+ // ... finally collect existence checks and abort the transaction if any of them failed.
+ final Entry<YangInstanceIdentifier, ReadFailedException> failure;
+ try {
+ failure = check.getFailure();
+ } catch (InterruptedException e) {
+ rwTransaction.cancel();
+ throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
+ }
+
+ if (failure != null) {
+ rwTransaction.cancel();
+ final ReadFailedException e = failure.getValue();
+ if (e == null) {
+ throw new RestconfDocumentedException("Data already exists for path: " + failure.getKey(),
+ ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS);
+ }
+
+ throw new RestconfDocumentedException("Could not determine the existence of path " + failure.getKey(), e,
+ e.getErrorList());
+ }
+ }
+
+ private void simplePostPut(final DOMDataTreeReadWriteTransaction rwTransaction,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext) {
+ checkItemDoesNotExists(rwTransaction, datastore, path);
+ if (isMounted != null && !isMounted.get()) {
+ ensureParentsByMerge(datastore, path, rwTransaction, schemaContext);
+ }
+ rwTransaction.put(datastore, path, payload);
+ }
+
+ private static boolean doesItemExist(final DOMDataTreeReadWriteTransaction rwTransaction,
+ final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ try {
+ return rwTransaction.exists(store, path).get();
+ } catch (InterruptedException e) {
+ rwTransaction.cancel();
+ throw new RestconfDocumentedException("Could not determine the existence of path " + path, e);
+ } catch (ExecutionException e) {
+ rwTransaction.cancel();
+ throw RestconfDocumentedException.decodeAndThrow("Could not determine the existence of path " + path,
+ Throwables.getCauseAs(e, ReadFailedException.class));
+ }
+ }
+
+ /**
+ * Check if item already exists. Throws error if it does NOT already exist.
+ * @param rwTransaction Current transaction
+ * @param store Used datastore
+ * @param path Path to item to verify its existence
+ */
+ private static void checkItemExists(final DOMDataTreeReadWriteTransaction rwTransaction,
+ final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ if (!doesItemExist(rwTransaction, store, path)) {
+ LOG.trace("Operation via Restconf was not executed because data at {} does not exist", path);
+ rwTransaction.cancel();
+ throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
+ ErrorTag.DATA_MISSING);
+ }
+ }
+
+ /**
+ * Check if item does NOT already exist. Throws error if it already exists.
+ * @param rwTransaction Current transaction
+ * @param store Used datastore
+ * @param path Path to item to verify its existence
+ */
+ private static void checkItemDoesNotExists(final DOMDataTreeReadWriteTransaction rwTransaction,
+ final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ if (doesItemExist(rwTransaction, store, path)) {
+ LOG.trace("Operation via Restconf was not executed because data at {} already exists", path);
+ rwTransaction.cancel();
+ throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
+ ErrorTag.DATA_EXISTS);
+ }
+ }
+
+ /**
+ * PUT data and submit {@link DOMDataReadWriteTransaction}.
+ *
+ * @param point
+ * point
+ * @param insert
+ * insert
+ */
+ private FluentFuture<? extends CommitInfo> putDataViaTransaction(
+ final DOMDataTreeReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext, final String insert, final String point) {
+ LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
+ putData(readWriteTransaction, datastore, path, payload, schemaContext, insert, point);
+ return readWriteTransaction.commit();
+ }
+
+ /**
+ * PUT data and do NOT submit {@link DOMDataReadWriteTransaction}.
+ */
+ private void putDataWithinTransaction(
+ final DOMDataTreeReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext) {
+ LOG.trace("Put {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
+ putData(writeTransaction, datastore, path, payload, schemaContext, null, null);
+ }
+
+ // FIXME: This is doing correct put for container and list children, not sure if this will work for choice case
+ private void putData(final DOMDataTreeReadWriteTransaction rwTransaction, final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext, final String insert, final String point) {
+ if (insert == null) {
+ makePut(rwTransaction, datastore, path, payload, schemaContext);
+ return;
+ }
+
+ final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path);
+ checkItemDoesNotExists(rwTransaction, datastore, path);
+ switch (insert) {
+ case "first":
+ if (schemaNode instanceof ListSchemaNode) {
+ final UserMapNode readList = (UserMapNode) this.readConfigurationData(path.getParent());
+ if (readList == null || readList.isEmpty()) {
+ simplePut(datastore, path, rwTransaction, schemaContext, payload);
+ } else {
+ rwTransaction.delete(datastore, path.getParent());
+ simplePut(datastore, path, rwTransaction, schemaContext, payload);
+ makePut(rwTransaction, datastore, path.getParent(), readList, schemaContext);
+ }
+ } else {
+ final UserLeafSetNode<?> readLeafList =
+ (UserLeafSetNode<?>) readConfigurationData(path.getParent());
+ if (readLeafList == null || readLeafList.isEmpty()) {
+ simplePut(datastore, path, rwTransaction, schemaContext, payload);
+ } else {
+ rwTransaction.delete(datastore, path.getParent());
+ simplePut(datastore, path, rwTransaction, schemaContext, payload);
+ makePut(rwTransaction, datastore, path.getParent(), readLeafList,
+ schemaContext);
+ }
+ }
+ break;
+ case "last":
+ simplePut(datastore, path, rwTransaction, schemaContext, payload);
+ break;
+ case "before":
+ if (schemaNode instanceof ListSchemaNode) {
+ final UserMapNode readList = (UserMapNode) this.readConfigurationData(path.getParent());
+ if (readList == null || readList.isEmpty()) {
+ simplePut(datastore, path, rwTransaction, schemaContext, payload);
+ } else {
+ insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
+ readList, true);
+ }
+ } else {
+ final UserLeafSetNode<?> readLeafList =
+ (UserLeafSetNode<?>) readConfigurationData(path.getParent());
+ if (readLeafList == null || readLeafList.isEmpty()) {
+ simplePut(datastore, path, rwTransaction, schemaContext, payload);
+ } else {
+ insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
+ readLeafList, true);
+ }
+ }
+ break;
+ case "after":
+ if (schemaNode instanceof ListSchemaNode) {
+ final UserMapNode readList = (UserMapNode) this.readConfigurationData(path.getParent());
+ if (readList == null || readList.isEmpty()) {
+ simplePut(datastore, path, rwTransaction, schemaContext, payload);
+ } else {
+ insertWithPointListPut(rwTransaction, datastore, path, payload, schemaContext, point,
+ readList, false);
+ }
+ } else {
+ final UserLeafSetNode<?> readLeafList =
+ (UserLeafSetNode<?>) readConfigurationData(path.getParent());
+ if (readLeafList == null || readLeafList.isEmpty()) {
+ simplePut(datastore, path, rwTransaction, schemaContext, payload);
+ } else {
+ insertWithPointLeafListPut(rwTransaction, datastore, path, payload, schemaContext, point,
+ readLeafList, false);
+ }
+ }
+ break;
+ default:
+ throw new RestconfDocumentedException(
+ "Used bad value of insert parameter. Possible values are first, last, before or after, but was: "
+ + insert);
+ }
+ }
+
+ private void insertWithPointLeafListPut(final DOMDataTreeWriteTransaction tx,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext, final String point, final UserLeafSetNode<?> readLeafList,
+ final boolean before) {
+ tx.delete(datastore, path.getParent());
+ final InstanceIdentifierContext instanceIdentifier = controllerContext.toInstanceIdentifier(point);
+ int index1 = 0;
+ for (final LeafSetEntryNode<?> nodeChild : readLeafList.body()) {
+ if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
+ break;
+ }
+ index1++;
+ }
+ if (!before) {
+ index1++;
+ }
+ int index2 = 0;
+ final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
+ tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ for (final LeafSetEntryNode<?> nodeChild : readLeafList.body()) {
+ if (index2 == index1) {
+ simplePut(datastore, path, tx, schemaContext, payload);
+ }
+ final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier());
+ tx.put(datastore, childPath, nodeChild);
+ index2++;
+ }
+ }
+
+ private void insertWithPointListPut(final DOMDataTreeWriteTransaction tx, final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path, final NormalizedNode payload, final EffectiveModelContext schemaContext,
+ final String point, final UserMapNode readList, final boolean before) {
+ tx.delete(datastore, path.getParent());
+ final InstanceIdentifierContext instanceIdentifier = controllerContext.toInstanceIdentifier(point);
+ int index1 = 0;
+ for (final MapEntryNode mapEntryNode : readList.body()) {
+ if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) {
+ break;
+ }
+ index1++;
+ }
+ if (!before) {
+ index1++;
+ }
+ int index2 = 0;
+ final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path.getParent());
+ tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ for (final MapEntryNode mapEntryNode : readList.body()) {
+ if (index2 == index1) {
+ simplePut(datastore, path, tx, schemaContext, payload);
+ }
+ final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier());
+ tx.put(datastore, childPath, mapEntryNode);
+ index2++;
+ }
+ }
+
+ private void makePut(final DOMDataTreeWriteTransaction tx, final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext) {
+ if (payload instanceof MapNode) {
+ final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
+ if (isMounted != null && !isMounted.get()) {
+ tx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+ ensureParentsByMerge(datastore, path, tx, schemaContext);
+ }
+ for (final MapEntryNode child : ((MapNode) payload).body()) {
+ final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
+ tx.put(datastore, childPath, child);
+ }
+ } else {
+ simplePut(datastore, path, tx, schemaContext, payload);
+ }
+ }
+
+ private void simplePut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path,
+ final DOMDataTreeWriteTransaction tx, final EffectiveModelContext schemaContext,
+ final NormalizedNode payload) {
+ if (isMounted != null && !isMounted.get()) {
+ ensureParentsByMerge(datastore, path, tx, schemaContext);
+ }
+ tx.put(datastore, path, payload);
+ }
+
+ private static FluentFuture<? extends CommitInfo> deleteDataViaTransaction(
+ final DOMDataTreeReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path) {
+ LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
+ checkItemExists(readWriteTransaction, datastore, path);
+ readWriteTransaction.delete(datastore, path);
+ return readWriteTransaction.commit();
+ }
+
+ private static void deleteDataWithinTransaction(final DOMDataTreeWriteTransaction tx,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
+ LOG.trace("Delete {} within Restconf Patch: {}", datastore.name(), path);
+ tx.delete(datastore, path);
+ }
+
+ private static void mergeDataWithinTransaction(final DOMDataTreeWriteTransaction tx,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext) {
+ LOG.trace("Merge {} within Restconf Patch: {} with payload {}", datastore.name(), path, payload);
+ ensureParentsByMerge(datastore, path, tx, schemaContext);
+
+ // Since YANG Patch provides the option to specify what kind of operation for each edit,
+ // OpenDaylight should not change it.
+ tx.merge(datastore, path, payload);
+ }
+
+ public void registerToListenNotification(final NotificationListenerAdapter listener) {
+ if (listener.isListening()) {
+ return;
+ }
+
+ final ListenerRegistration<DOMNotificationListener> registration = domNotification
+ .registerNotificationListener(listener, listener.getSchemaPath());
+
+ listener.setRegistration(registration);
+ }
+
+ private static void ensureParentsByMerge(final LogicalDatastoreType store,
+ final YangInstanceIdentifier normalizedPath, final DOMDataTreeWriteTransaction tx,
+ final EffectiveModelContext schemaContext) {
+ final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
+ YangInstanceIdentifier rootNormalizedPath = null;
+
+ final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
+
+ while (it.hasNext()) {
+ final PathArgument pathArgument = it.next();
+ if (rootNormalizedPath == null) {
+ rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
+ }
+
+ if (it.hasNext()) {
+ normalizedPathWithoutChildArgs.add(pathArgument);
+ }
+ }
+
+ if (normalizedPathWithoutChildArgs.isEmpty()) {
+ return;
+ }
+
+ checkArgument(rootNormalizedPath != null, "Empty path received");
+ tx.merge(store, rootNormalizedPath, ImmutableNodes.fromInstanceId(schemaContext,
+ YangInstanceIdentifier.create(normalizedPathWithoutChildArgs)));
+ }
+
+ private static RestconfDocumentedException dataBrokerUnavailable(final YangInstanceIdentifier path) {
+ LOG.warn("DOM data broker service is not available for mount point {}", path);
+ return new RestconfDocumentedException("DOM data broker service is not available for mount point " + path);
+ }
+
+ private static EffectiveModelContext modelContext(final DOMMountPoint mountPoint) {
+ return mountPoint.getService(DOMSchemaService.class)
+ .flatMap(svc -> Optional.ofNullable(svc.getGlobalContext()))
+ .orElse(null);
+ }
+
+ private static final class PatchStatusContextHelper {
+ PatchStatusContext status;
+
+ public PatchStatusContext getStatus() {
+ return status;
+ }
+
+ public void setStatus(final PatchStatusContext status) {
+ this.status = status;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/ControllerContext.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/ControllerContext.java
new file mode 100644
index 0000000..8e05bf1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/ControllerContext.java
@@ -0,0 +1,1006 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.io.Closeable;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.core.Response.Status;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMMountPointService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.Draft02.RestConfModule;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.util.RestUtil;
+import org.opendaylight.yangtools.concepts.IllegalArgumentCodec;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextListener;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public final class ControllerContext implements EffectiveModelContextListener, Closeable {
+ // FIXME: this should be in md-sal somewhere
+ public static final String MOUNT = "yang-ext:mount";
+
+ private static final Logger LOG = LoggerFactory.getLogger(ControllerContext.class);
+
+ private static final String NULL_VALUE = "null";
+
+ private static final String MOUNT_MODULE = "yang-ext";
+
+ private static final String MOUNT_NODE = "mount";
+
+ private static final Splitter SLASH_SPLITTER = Splitter.on('/');
+
+ private final AtomicReference<Map<QName, RpcDefinition>> qnameToRpc = new AtomicReference<>(Collections.emptyMap());
+
+ private final DOMMountPointService mountService;
+ private final DOMYangTextSourceProvider yangTextSourceProvider;
+ private final ListenerRegistration<?> listenerRegistration;
+ private volatile EffectiveModelContext globalSchema;
+ private volatile DataNormalizer dataNormalizer;
+
+ @Inject
+ public ControllerContext(final DOMSchemaService schemaService, final DOMMountPointService mountService,
+ final DOMSchemaService domSchemaService) {
+ this.mountService = mountService;
+ yangTextSourceProvider = domSchemaService.getExtensions().getInstance(DOMYangTextSourceProvider.class);
+
+ onModelContextUpdated(schemaService.getGlobalContext());
+ listenerRegistration = schemaService.registerSchemaContextListener(this);
+ }
+
+ /**
+ * Factory method.
+ *
+ * @deprecated Just use the
+ * {@link #ControllerContext(DOMSchemaService, DOMMountPointService, DOMSchemaService)}
+ * constructor instead.
+ */
+ @Deprecated
+ public static ControllerContext newInstance(final DOMSchemaService schemaService,
+ final DOMMountPointService mountService, final DOMSchemaService domSchemaService) {
+ return new ControllerContext(schemaService, mountService, domSchemaService);
+ }
+
+ private void setGlobalSchema(final EffectiveModelContext globalSchema) {
+ this.globalSchema = globalSchema;
+ dataNormalizer = new DataNormalizer(globalSchema);
+ }
+
+ public DOMYangTextSourceProvider getYangTextSourceProvider() {
+ return yangTextSourceProvider;
+ }
+
+ private void checkPreconditions() {
+ if (globalSchema == null) {
+ throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
+ }
+ }
+
+ @Override
+ @PreDestroy
+ public void close() {
+ listenerRegistration.close();
+ }
+
+ public void setSchemas(final EffectiveModelContext schemas) {
+ onModelContextUpdated(schemas);
+ }
+
+ public InstanceIdentifierContext toInstanceIdentifier(final String restconfInstance) {
+ return toIdentifier(restconfInstance, false);
+ }
+
+ public EffectiveModelContext getGlobalSchema() {
+ return globalSchema;
+ }
+
+ public InstanceIdentifierContext toMountPointIdentifier(final String restconfInstance) {
+ return toIdentifier(restconfInstance, true);
+ }
+
+ private InstanceIdentifierContext toIdentifier(final String restconfInstance,
+ final boolean toMountPointIdentifier) {
+ checkPreconditions();
+
+ if (restconfInstance == null) {
+ return InstanceIdentifierContext.ofLocalRoot(globalSchema);
+ }
+
+ final List<String> pathArgs = urlPathArgsDecode(SLASH_SPLITTER.split(restconfInstance));
+ omitFirstAndLastEmptyString(pathArgs);
+ if (pathArgs.isEmpty()) {
+ return null;
+ }
+
+ final String first = pathArgs.iterator().next();
+ final String startModule = toModuleName(first);
+ if (startModule == null) {
+ throw new RestconfDocumentedException("First node in URI has to be in format \"moduleName:nodeName\"",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ final Collection<? extends Module> latestModule = globalSchema.findModules(startModule);
+ if (latestModule.isEmpty()) {
+ throw new RestconfDocumentedException("The module named '" + startModule + "' does not exist.",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
+ }
+
+ final InstanceIdentifierContext iiWithSchemaNode = collectPathArguments(YangInstanceIdentifier.builder(),
+ new ArrayDeque<>(), pathArgs, latestModule.iterator().next(), null, toMountPointIdentifier);
+
+ if (iiWithSchemaNode == null) {
+ throw new RestconfDocumentedException("URI has bad format", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ return iiWithSchemaNode;
+ }
+
+ private static List<String> omitFirstAndLastEmptyString(final List<String> list) {
+ if (list.isEmpty()) {
+ return list;
+ }
+
+ final String head = list.iterator().next();
+ if (head.isEmpty()) {
+ list.remove(0);
+ }
+
+ if (list.isEmpty()) {
+ return list;
+ }
+
+ final String last = list.get(list.size() - 1);
+ if (last.isEmpty()) {
+ list.remove(list.size() - 1);
+ }
+
+ return list;
+ }
+
+ public Module findModuleByName(final String moduleName) {
+ checkPreconditions();
+ checkArgument(moduleName != null && !moduleName.isEmpty());
+ return globalSchema.findModules(moduleName).stream().findFirst().orElse(null);
+ }
+
+ public static Module findModuleByName(final DOMMountPoint mountPoint, final String moduleName) {
+ checkArgument(moduleName != null && mountPoint != null);
+
+ final EffectiveModelContext mountPointSchema = getModelContext(mountPoint);
+ return mountPointSchema == null ? null
+ : mountPointSchema.findModules(moduleName).stream().findFirst().orElse(null);
+ }
+
+ public Module findModuleByNamespace(final XMLNamespace namespace) {
+ checkPreconditions();
+ checkArgument(namespace != null);
+ return globalSchema.findModules(namespace).stream().findFirst().orElse(null);
+ }
+
+ public static Module findModuleByNamespace(final DOMMountPoint mountPoint, final XMLNamespace namespace) {
+ checkArgument(namespace != null && mountPoint != null);
+
+ final EffectiveModelContext mountPointSchema = getModelContext(mountPoint);
+ return mountPointSchema == null ? null
+ : mountPointSchema.findModules(namespace).stream().findFirst().orElse(null);
+ }
+
+ public Module findModuleByNameAndRevision(final String name, final Revision revision) {
+ checkPreconditions();
+ checkArgument(name != null && revision != null);
+
+ return globalSchema.findModule(name, revision).orElse(null);
+ }
+
+ public Module findModuleByNameAndRevision(final DOMMountPoint mountPoint, final String name,
+ final Revision revision) {
+ checkPreconditions();
+ checkArgument(name != null && revision != null && mountPoint != null);
+
+ final EffectiveModelContext schemaContext = getModelContext(mountPoint);
+ return schemaContext == null ? null : schemaContext.findModule(name, revision).orElse(null);
+ }
+
+ public DataNodeContainer getDataNodeContainerFor(final YangInstanceIdentifier path) {
+ checkPreconditions();
+
+ final Iterable<PathArgument> elements = path.getPathArguments();
+ final PathArgument head = elements.iterator().next();
+ final QName startQName = head.getNodeType();
+ final Module initialModule = globalSchema.findModule(startQName.getModule()).orElse(null);
+ DataNodeContainer node = initialModule;
+ for (final PathArgument element : elements) {
+ final QName _nodeType = element.getNodeType();
+ final DataSchemaNode potentialNode = childByQName(node, _nodeType);
+ if (potentialNode == null || !isListOrContainer(potentialNode)) {
+ return null;
+ }
+ node = (DataNodeContainer) potentialNode;
+ }
+
+ return node;
+ }
+
+ public String toFullRestconfIdentifier(final YangInstanceIdentifier path, final DOMMountPoint mount) {
+ checkPreconditions();
+
+ final Iterable<PathArgument> elements = path.getPathArguments();
+ final StringBuilder builder = new StringBuilder();
+ final PathArgument head = elements.iterator().next();
+ final QName startQName = head.getNodeType();
+ final EffectiveModelContext schemaContext;
+ if (mount != null) {
+ schemaContext = getModelContext(mount);
+ } else {
+ schemaContext = globalSchema;
+ }
+ final Module initialModule = schemaContext.findModule(startQName.getModule()).orElse(null);
+ DataNodeContainer node = initialModule;
+ for (final PathArgument element : elements) {
+ if (!(element instanceof AugmentationIdentifier)) {
+ final QName _nodeType = element.getNodeType();
+ final DataSchemaNode potentialNode = childByQName(node, _nodeType);
+ if ((!(element instanceof NodeIdentifier) || !(potentialNode instanceof ListSchemaNode))
+ && !(potentialNode instanceof ChoiceSchemaNode)) {
+ builder.append(convertToRestconfIdentifier(element, potentialNode, mount));
+ if (potentialNode instanceof DataNodeContainer) {
+ node = (DataNodeContainer) potentialNode;
+ }
+ }
+ }
+ }
+
+ return builder.toString();
+ }
+
+ public String findModuleNameByNamespace(final XMLNamespace namespace) {
+ checkPreconditions();
+
+ final Module module = findModuleByNamespace(namespace);
+ return module == null ? null : module.getName();
+ }
+
+ public static String findModuleNameByNamespace(final DOMMountPoint mountPoint, final XMLNamespace namespace) {
+ final Module module = findModuleByNamespace(mountPoint, namespace);
+ return module == null ? null : module.getName();
+ }
+
+ public XMLNamespace findNamespaceByModuleName(final String moduleName) {
+ final Module module = findModuleByName(moduleName);
+ return module == null ? null : module.getNamespace();
+ }
+
+ public static XMLNamespace findNamespaceByModuleName(final DOMMountPoint mountPoint, final String moduleName) {
+ final Module module = findModuleByName(mountPoint, moduleName);
+ return module == null ? null : module.getNamespace();
+ }
+
+ public Collection<? extends Module> getAllModules(final DOMMountPoint mountPoint) {
+ checkPreconditions();
+
+ final EffectiveModelContext schemaContext = mountPoint == null ? null : getModelContext(mountPoint);
+ return schemaContext == null ? null : schemaContext.getModules();
+ }
+
+ public Collection<? extends Module> getAllModules() {
+ checkPreconditions();
+ return globalSchema.getModules();
+ }
+
+ private static String toRestconfIdentifier(final EffectiveModelContext context, final QName qname) {
+ final Module schema = context.findModule(qname.getModule()).orElse(null);
+ return schema == null ? null : schema.getName() + ':' + qname.getLocalName();
+ }
+
+ public String toRestconfIdentifier(final QName qname, final DOMMountPoint mountPoint) {
+ return mountPoint != null ? toRestconfIdentifier(getModelContext(mountPoint), qname)
+ : toRestconfIdentifier(qname);
+ }
+
+ public String toRestconfIdentifier(final QName qname) {
+ checkPreconditions();
+
+ return toRestconfIdentifier(globalSchema, qname);
+ }
+
+ public static String toRestconfIdentifier(final DOMMountPoint mountPoint, final QName qname) {
+ return mountPoint == null ? null : toRestconfIdentifier(getModelContext(mountPoint), qname);
+ }
+
+ public Module getRestconfModule() {
+ return findModuleByNameAndRevision(Draft02.RestConfModule.NAME, Revision.of(Draft02.RestConfModule.REVISION));
+ }
+
+ public Entry<SchemaInferenceStack, ContainerSchemaNode> getRestconfModuleErrorsSchemaNode() {
+ checkPreconditions();
+
+ final var schema = globalSchema;
+ final var namespace = QNameModule.create(XMLNamespace.of(Draft02.RestConfModule.NAMESPACE),
+ Revision.of(Draft02.RestConfModule.REVISION));
+ if (schema.findModule(namespace).isEmpty()) {
+ return null;
+ }
+
+ final var stack = SchemaInferenceStack.of(globalSchema);
+ stack.enterGrouping(RestConfModule.ERRORS_QNAME);
+ final var stmt = stack.enterSchemaTree(RestConfModule.ERRORS_QNAME);
+ verify(stmt instanceof ContainerSchemaNode, "Unexpected statement %s", stmt);
+ return Map.entry(stack, (ContainerSchemaNode) stmt);
+ }
+
+ public DataSchemaNode getRestconfModuleRestConfSchemaNode(final Module inRestconfModule,
+ final String schemaNodeName) {
+ Module restconfModule = inRestconfModule;
+ if (restconfModule == null) {
+ restconfModule = getRestconfModule();
+ }
+
+ if (restconfModule == null) {
+ return null;
+ }
+
+ final Collection<? extends GroupingDefinition> groupings = restconfModule.getGroupings();
+ final Iterable<? extends GroupingDefinition> filteredGroups = Iterables.filter(groupings,
+ g -> RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE.equals(g.getQName().getLocalName()));
+ final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null);
+
+ final var instanceDataChildrenByName = findInstanceDataChildrenByName(restconfGrouping,
+ RestConfModule.RESTCONF_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode restconfContainer = getFirst(instanceDataChildrenByName);
+
+ if (RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE.equals(schemaNodeName)) {
+ final var instances = findInstanceDataChildrenByName(
+ (DataNodeContainer) restconfContainer, RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
+ return getFirst(instances);
+ } else if (RestConfModule.STREAM_LIST_SCHEMA_NODE.equals(schemaNodeName)) {
+ var instances = findInstanceDataChildrenByName(
+ (DataNodeContainer) restconfContainer, RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode modules = getFirst(instances);
+ instances = findInstanceDataChildrenByName((DataNodeContainer) modules,
+ RestConfModule.STREAM_LIST_SCHEMA_NODE);
+ return getFirst(instances);
+ } else if (RestConfModule.MODULES_CONTAINER_SCHEMA_NODE.equals(schemaNodeName)) {
+ final var instances = findInstanceDataChildrenByName(
+ (DataNodeContainer) restconfContainer, RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
+ return getFirst(instances);
+ } else if (RestConfModule.MODULE_LIST_SCHEMA_NODE.equals(schemaNodeName)) {
+ var instances = findInstanceDataChildrenByName(
+ (DataNodeContainer) restconfContainer, RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode modules = getFirst(instances);
+ instances = findInstanceDataChildrenByName((DataNodeContainer) modules,
+ RestConfModule.MODULE_LIST_SCHEMA_NODE);
+ return getFirst(instances);
+ } else if (RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE.equals(schemaNodeName)) {
+ final var instances = findInstanceDataChildrenByName(
+ (DataNodeContainer) restconfContainer, RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
+ return getFirst(instances);
+ }
+
+ return null;
+ }
+
+ public static @Nullable DataSchemaNode getFirst(final List<FoundChild> children) {
+ return children.isEmpty() ? null : children.get(0).child;
+ }
+
+ private static DataSchemaNode childByQName(final ChoiceSchemaNode container, final QName name) {
+ for (final CaseSchemaNode caze : container.getCases()) {
+ final DataSchemaNode ret = childByQName(caze, name);
+ if (ret != null) {
+ return ret;
+ }
+ }
+
+ return null;
+ }
+
+ private static DataSchemaNode childByQName(final CaseSchemaNode container, final QName name) {
+ return container.dataChildByName(name);
+ }
+
+ private static DataSchemaNode childByQName(final ContainerSchemaNode container, final QName name) {
+ return dataNodeChildByQName(container, name);
+ }
+
+ private static DataSchemaNode childByQName(final ListSchemaNode container, final QName name) {
+ return dataNodeChildByQName(container, name);
+ }
+
+ private static DataSchemaNode childByQName(final Module container, final QName name) {
+ return dataNodeChildByQName(container, name);
+ }
+
+ private static DataSchemaNode childByQName(final DataSchemaNode container, final QName name) {
+ return null;
+ }
+
+
+ private static DataSchemaNode childByQName(final Object container, final QName name) {
+ if (container instanceof CaseSchemaNode) {
+ return childByQName((CaseSchemaNode) container, name);
+ } else if (container instanceof ChoiceSchemaNode) {
+ return childByQName((ChoiceSchemaNode) container, name);
+ } else if (container instanceof ContainerSchemaNode) {
+ return childByQName((ContainerSchemaNode) container, name);
+ } else if (container instanceof ListSchemaNode) {
+ return childByQName((ListSchemaNode) container, name);
+ } else if (container instanceof DataSchemaNode) {
+ return childByQName((DataSchemaNode) container, name);
+ } else if (container instanceof Module) {
+ return childByQName((Module) container, name);
+ } else {
+ throw new IllegalArgumentException("Unhandled parameter types: "
+ + Arrays.asList(container, name).toString());
+ }
+ }
+
+ private static DataSchemaNode dataNodeChildByQName(final DataNodeContainer container, final QName name) {
+ final DataSchemaNode ret = container.dataChildByName(name);
+ if (ret == null) {
+ for (final DataSchemaNode node : container.getChildNodes()) {
+ if (node instanceof ChoiceSchemaNode) {
+ final ChoiceSchemaNode choiceNode = (ChoiceSchemaNode) node;
+ final DataSchemaNode childByQName = childByQName(choiceNode, name);
+ if (childByQName != null) {
+ return childByQName;
+ }
+ }
+ }
+ }
+ return ret;
+ }
+
+ private String toUriString(final Object object, final LeafSchemaNode leafNode, final DOMMountPoint mount)
+ throws UnsupportedEncodingException {
+ final IllegalArgumentCodec<Object, Object> codec = RestCodec.from(leafNode.getType(), mount, this);
+ return object == null ? "" : URLEncoder.encode(codec.serialize(object).toString(), StandardCharsets.UTF_8);
+ }
+
+ @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", justification = "Unrecognised NullableDecl")
+ private InstanceIdentifierContext collectPathArguments(final InstanceIdentifierBuilder builder,
+ final Deque<QName> schemaPath, final List<String> strings, final DataNodeContainer parentNode,
+ final DOMMountPoint mountPoint, final boolean returnJustMountPoint) {
+ requireNonNull(strings);
+
+ if (parentNode == null) {
+ return null;
+ }
+
+ if (strings.isEmpty()) {
+ return createContext(builder.build(), (DataSchemaNode) parentNode, mountPoint,
+ mountPoint != null ? getModelContext(mountPoint) : globalSchema);
+ }
+
+ final String head = strings.iterator().next();
+
+ if (head.isEmpty()) {
+ final List<String> remaining = strings.subList(1, strings.size());
+ return collectPathArguments(builder, schemaPath, remaining, parentNode, mountPoint, returnJustMountPoint);
+ }
+
+ final String nodeName = toNodeName(head);
+ final String moduleName = toModuleName(head);
+
+ DataSchemaNode targetNode = null;
+ if (!Strings.isNullOrEmpty(moduleName)) {
+ if (MOUNT_MODULE.equals(moduleName) && MOUNT_NODE.equals(nodeName)) {
+ if (mountPoint != null) {
+ throw new RestconfDocumentedException("Restconf supports just one mount point in URI.",
+ ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED);
+ }
+
+ if (mountService == null) {
+ throw new RestconfDocumentedException(
+ "MountService was not found. Finding behind mount points does not work.",
+ ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED);
+ }
+
+ final YangInstanceIdentifier partialPath = dataNormalizer.toNormalized(builder.build()).getKey();
+ final Optional<DOMMountPoint> mountOpt = mountService.getMountPoint(partialPath);
+ if (mountOpt.isEmpty()) {
+ LOG.debug("Instance identifier to missing mount point: {}", partialPath);
+ throw new RestconfDocumentedException("Mount point does not exist.", ErrorType.PROTOCOL,
+ ErrorTag.DATA_MISSING);
+ }
+ final DOMMountPoint mount = mountOpt.get();
+
+ final EffectiveModelContext mountPointSchema = getModelContext(mount);
+ if (mountPointSchema == null) {
+ throw new RestconfDocumentedException("Mount point does not contain any schema with modules.",
+ ErrorType.APPLICATION, ErrorTag.UNKNOWN_ELEMENT);
+ }
+
+ if (returnJustMountPoint || strings.size() == 1) {
+ return InstanceIdentifierContext.ofMountPointRoot(mount, mountPointSchema);
+ }
+
+ final String moduleNameBehindMountPoint = toModuleName(strings.get(1));
+ if (moduleNameBehindMountPoint == null) {
+ throw new RestconfDocumentedException(
+ "First node after mount point in URI has to be in format \"moduleName:nodeName\"",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ final Iterator<? extends Module> it = mountPointSchema.findModules(moduleNameBehindMountPoint)
+ .iterator();
+ if (!it.hasNext()) {
+ throw new RestconfDocumentedException("\"" + moduleNameBehindMountPoint
+ + "\" module does not exist in mount point.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
+ }
+
+ final List<String> subList = strings.subList(1, strings.size());
+ return collectPathArguments(YangInstanceIdentifier.builder(), new ArrayDeque<>(), subList, it.next(),
+ mount, returnJustMountPoint);
+ }
+
+ Module module = null;
+ if (mountPoint == null) {
+ checkPreconditions();
+ module = globalSchema.findModules(moduleName).stream().findFirst().orElse(null);
+ if (module == null) {
+ throw new RestconfDocumentedException("\"" + moduleName + "\" module does not exist.",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
+ }
+ } else {
+ final EffectiveModelContext schemaContext = getModelContext(mountPoint);
+ if (schemaContext != null) {
+ module = schemaContext.findModules(moduleName).stream().findFirst().orElse(null);
+ } else {
+ module = null;
+ }
+ if (module == null) {
+ throw new RestconfDocumentedException("\"" + moduleName
+ + "\" module does not exist in mount point.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
+ }
+ }
+
+ final var found = findInstanceDataChildByNameAndNamespace(parentNode, nodeName, module.getNamespace());
+ if (found == null) {
+ if (parentNode instanceof Module) {
+ final RpcDefinition rpc;
+ if (mountPoint == null) {
+ rpc = getRpcDefinition(head, module.getRevision());
+ } else {
+ rpc = getRpcDefinition(module, toNodeName(head));
+ }
+ if (rpc != null) {
+ final var ctx = mountPoint == null ? globalSchema : getModelContext(mountPoint);
+ return InstanceIdentifierContext.ofRpcInput(ctx, rpc, mountPoint);
+ }
+ }
+ throw new RestconfDocumentedException("URI has bad format. Possible reasons:\n" + " 1. \"" + head
+ + "\" was not found in parent data node.\n" + " 2. \"" + head
+ + "\" is behind mount point. Then it should be in format \"/" + MOUNT + "/" + head + "\".",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ targetNode = found.child;
+ schemaPath.addAll(found.intermediate);
+ schemaPath.add(targetNode.getQName());
+ } else {
+ final var potentialSchemaNodes = findInstanceDataChildrenByName(parentNode, nodeName);
+ if (potentialSchemaNodes.size() > 1) {
+ final StringBuilder strBuilder = new StringBuilder();
+ for (var potentialNodeSchema : potentialSchemaNodes) {
+ strBuilder.append(" ").append(potentialNodeSchema.child.getQName().getNamespace()).append("\n");
+ }
+
+ throw new RestconfDocumentedException(
+ "URI has bad format. Node \""
+ + nodeName + "\" is added as augment from more than one module. "
+ + "Therefore the node must have module name "
+ + "and it has to be in format \"moduleName:nodeName\"."
+ + "\nThe node is added as augment from modules with namespaces:\n"
+ + strBuilder.toString(), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ if (potentialSchemaNodes.isEmpty()) {
+ throw new RestconfDocumentedException("\"" + nodeName + "\" in URI was not found in parent data node",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
+ }
+
+ final var found = potentialSchemaNodes.get(0);
+ targetNode = found.child;
+ schemaPath.addAll(found.intermediate);
+ schemaPath.add(targetNode.getQName());
+ }
+
+ if (!isListOrContainer(targetNode)) {
+ throw new RestconfDocumentedException("URI has bad format. Node \"" + head
+ + "\" must be Container or List yang type.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ int consumed = 1;
+ if (targetNode instanceof ListSchemaNode) {
+ final ListSchemaNode listNode = (ListSchemaNode) targetNode;
+ final int keysSize = listNode.getKeyDefinition().size();
+ if (strings.size() - consumed < keysSize) {
+ throw new RestconfDocumentedException("Missing key for list \"" + listNode.getQName().getLocalName()
+ + "\".", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+ }
+
+ final List<String> uriKeyValues = strings.subList(consumed, consumed + keysSize);
+ final HashMap<QName, Object> keyValues = new HashMap<>();
+ int index = 0;
+ for (final QName key : listNode.getKeyDefinition()) {
+ final String uriKeyValue = uriKeyValues.get(index);
+ if (uriKeyValue.equals(NULL_VALUE)) {
+ throw new RestconfDocumentedException("URI has bad format. List \""
+ + listNode.getQName().getLocalName() + "\" cannot contain \"null\" value as a key.",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ final var keyChild = listNode.getDataChildByName(key);
+ schemaPath.addLast(keyChild.getQName());
+ addKeyValue(keyValues, schemaPath, keyChild, uriKeyValue, mountPoint);
+ schemaPath.removeLast();
+ index++;
+ }
+
+ consumed = consumed + index;
+ builder.nodeWithKey(targetNode.getQName(), keyValues);
+ } else {
+ builder.node(targetNode.getQName());
+ }
+
+ if (targetNode instanceof DataNodeContainer) {
+ final List<String> remaining = strings.subList(consumed, strings.size());
+ return collectPathArguments(builder, schemaPath, remaining, (DataNodeContainer) targetNode, mountPoint,
+ returnJustMountPoint);
+ }
+
+ return createContext(builder.build(), targetNode, mountPoint,
+ mountPoint != null ? getModelContext(mountPoint) : globalSchema);
+ }
+
+ private static InstanceIdentifierContext createContext(final YangInstanceIdentifier instance,
+ final DataSchemaNode dataSchemaNode, final DOMMountPoint mountPoint,
+ final EffectiveModelContext schemaContext) {
+ final var normalized = new DataNormalizer(schemaContext).toNormalized(instance);
+ return InstanceIdentifierContext.ofPath(normalized.getValue(), dataSchemaNode, normalized.getKey(), mountPoint);
+ }
+
+ public static @Nullable FoundChild findInstanceDataChildByNameAndNamespace(final DataNodeContainer container,
+ final String name, final XMLNamespace namespace) {
+ requireNonNull(namespace);
+
+ for (var node : findInstanceDataChildrenByName(container, name)) {
+ if (namespace.equals(node.child.getQName().getNamespace())) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ public static List<FoundChild> findInstanceDataChildrenByName(final DataNodeContainer container,
+ final String name) {
+ final List<FoundChild> instantiatedDataNodeContainers = new ArrayList<>();
+ collectInstanceDataNodeContainers(instantiatedDataNodeContainers, requireNonNull(container),
+ requireNonNull(name), List.of());
+ return instantiatedDataNodeContainers;
+ }
+
+ private static void collectInstanceDataNodeContainers(final List<FoundChild> potentialSchemaNodes,
+ final DataNodeContainer container, final String name, final List<QName> intermediate) {
+ // We perform two iterations to retain breadth-first ordering
+ for (var child : container.getChildNodes()) {
+ if (name.equals(child.getQName().getLocalName()) && isInstantiatedDataSchema(child)) {
+ potentialSchemaNodes.add(new FoundChild(child, intermediate));
+ }
+ }
+
+ for (var child : container.getChildNodes()) {
+ if (child instanceof ChoiceSchemaNode) {
+ for (var caze : ((ChoiceSchemaNode) child).getCases()) {
+ collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name,
+ ImmutableList.<QName>builderWithExpectedSize(intermediate.size() + 2)
+ .addAll(intermediate).add(child.getQName()).add(caze.getQName())
+ .build());
+ }
+ }
+ }
+ }
+
+ public static boolean isInstantiatedDataSchema(final DataSchemaNode node) {
+ return node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode
+ || node instanceof ContainerSchemaNode || node instanceof ListSchemaNode
+ || node instanceof AnyxmlSchemaNode;
+ }
+
+ private void addKeyValue(final HashMap<QName, Object> map, final Deque<QName> schemaPath, final DataSchemaNode node,
+ final String uriValue, final DOMMountPoint mountPoint) {
+ checkArgument(node instanceof LeafSchemaNode);
+
+ final EffectiveModelContext schemaContext = mountPoint == null ? globalSchema : getModelContext(mountPoint);
+ final String urlDecoded = urlPathArgDecode(requireNonNull(uriValue));
+ TypeDefinition<?> typedef = ((LeafSchemaNode) node).getType();
+ final TypeDefinition<?> baseType = RestUtil.resolveBaseTypeFrom(typedef);
+ if (baseType instanceof LeafrefTypeDefinition) {
+ final var stack = SchemaInferenceStack.of(schemaContext);
+ schemaPath.forEach(stack::enterSchemaTree);
+ typedef = stack.resolveLeafref((LeafrefTypeDefinition) baseType);
+ }
+ final IllegalArgumentCodec<Object, Object> codec = RestCodec.from(typedef, mountPoint, this);
+ Object decoded = codec.deserialize(urlDecoded);
+ String additionalInfo = "";
+ if (decoded == null) {
+ if (typedef instanceof IdentityrefTypeDefinition) {
+ decoded = toQName(schemaContext, urlDecoded);
+ additionalInfo =
+ "For key which is of type identityref it should be in format module_name:identity_name.";
+ }
+ }
+
+ if (decoded == null) {
+ throw new RestconfDocumentedException(uriValue + " from URI can't be resolved. " + additionalInfo,
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ map.put(node.getQName(), decoded);
+ }
+
+ private static String toModuleName(final String str) {
+ final int idx = str.indexOf(':');
+ if (idx == -1) {
+ return null;
+ }
+
+ // Make sure there is only one occurrence
+ if (str.indexOf(':', idx + 1) != -1) {
+ return null;
+ }
+
+ return str.substring(0, idx);
+ }
+
+ private static String toNodeName(final String str) {
+ final int idx = str.indexOf(':');
+ if (idx == -1) {
+ return str;
+ }
+
+ // Make sure there is only one occurrence
+ if (str.indexOf(':', idx + 1) != -1) {
+ return str;
+ }
+
+ return str.substring(idx + 1);
+ }
+
+ private QName toQName(final EffectiveModelContext schemaContext, final String name,
+ final Optional<Revision> revisionDate) {
+ checkPreconditions();
+ final String module = toModuleName(name);
+ final String node = toNodeName(name);
+ final Module m = schemaContext.findModule(module, revisionDate).orElse(null);
+ return m == null ? null : QName.create(m.getQNameModule(), node);
+ }
+
+ private QName toQName(final EffectiveModelContext schemaContext, final String name) {
+ checkPreconditions();
+ final String module = toModuleName(name);
+ final String node = toNodeName(name);
+ final Collection<? extends Module> modules = schemaContext.findModules(module);
+ return modules.isEmpty() ? null : QName.create(modules.iterator().next().getQNameModule(), node);
+ }
+
+ private static boolean isListOrContainer(final DataSchemaNode node) {
+ return node instanceof ListSchemaNode || node instanceof ContainerSchemaNode;
+ }
+
+ public RpcDefinition getRpcDefinition(final String name, final Optional<Revision> revisionDate) {
+ final QName validName = toQName(globalSchema, name, revisionDate);
+ return validName == null ? null : qnameToRpc.get().get(validName);
+ }
+
+ public RpcDefinition getRpcDefinition(final String name) {
+ final QName validName = toQName(globalSchema, name);
+ return validName == null ? null : qnameToRpc.get().get(validName);
+ }
+
+ private static RpcDefinition getRpcDefinition(final Module module, final String rpcName) {
+ final QName rpcQName = QName.create(module.getQNameModule(), rpcName);
+ for (final RpcDefinition rpcDefinition : module.getRpcs()) {
+ if (rpcQName.equals(rpcDefinition.getQName())) {
+ return rpcDefinition;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void onModelContextUpdated(final EffectiveModelContext context) {
+ if (context != null) {
+ final Collection<? extends RpcDefinition> defs = context.getOperations();
+ final Map<QName, RpcDefinition> newMap = new HashMap<>(defs.size());
+
+ for (final RpcDefinition operation : defs) {
+ newMap.put(operation.getQName(), operation);
+ }
+
+ // FIXME: still not completely atomic
+ qnameToRpc.set(ImmutableMap.copyOf(newMap));
+ setGlobalSchema(context);
+ }
+ }
+
+ private static List<String> urlPathArgsDecode(final Iterable<String> strings) {
+ final List<String> decodedPathArgs = new ArrayList<>();
+ for (final String pathArg : strings) {
+ final String _decode = URLDecoder.decode(pathArg, StandardCharsets.UTF_8);
+ decodedPathArgs.add(_decode);
+ }
+ return decodedPathArgs;
+ }
+
+ static String urlPathArgDecode(final String pathArg) {
+ if (pathArg == null) {
+ return null;
+ }
+ return URLDecoder.decode(pathArg, StandardCharsets.UTF_8);
+ }
+
+ private String convertToRestconfIdentifier(final PathArgument argument, final DataSchemaNode node,
+ final DOMMountPoint mount) {
+ if (argument instanceof NodeIdentifier) {
+ return convertToRestconfIdentifier((NodeIdentifier) argument, mount);
+ } else if (argument instanceof NodeIdentifierWithPredicates && node instanceof ListSchemaNode) {
+ return convertToRestconfIdentifierWithPredicates((NodeIdentifierWithPredicates) argument,
+ (ListSchemaNode) node, mount);
+ } else if (argument != null && node != null) {
+ throw new IllegalArgumentException("Conversion of generic path argument is not supported");
+ } else {
+ throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.asList(argument, node));
+ }
+ }
+
+ private String convertToRestconfIdentifier(final NodeIdentifier argument, final DOMMountPoint node) {
+ return "/" + toRestconfIdentifier(argument.getNodeType(), node);
+ }
+
+ private String convertToRestconfIdentifierWithPredicates(final NodeIdentifierWithPredicates argument,
+ final ListSchemaNode node, final DOMMountPoint mount) {
+ final QName nodeType = argument.getNodeType();
+ final String nodeIdentifier = toRestconfIdentifier(nodeType, mount);
+
+ final StringBuilder builder = new StringBuilder().append('/').append(nodeIdentifier).append('/');
+
+ final List<QName> keyDefinition = node.getKeyDefinition();
+ boolean hasElements = false;
+ for (final QName key : keyDefinition) {
+ for (final DataSchemaNode listChild : node.getChildNodes()) {
+ if (listChild.getQName().equals(key)) {
+ if (!hasElements) {
+ hasElements = true;
+ } else {
+ builder.append('/');
+ }
+
+ checkState(listChild instanceof LeafSchemaNode,
+ "List key has to consist of leaves, not %s", listChild);
+
+ final Object value = argument.getValue(key);
+ try {
+ builder.append(toUriString(value, (LeafSchemaNode)listChild, mount));
+ } catch (final UnsupportedEncodingException e) {
+ LOG.error("Error parsing URI: {}", value, e);
+ return null;
+ }
+ break;
+ }
+ }
+ }
+
+ return builder.toString();
+ }
+
+ public YangInstanceIdentifier toXpathRepresentation(final YangInstanceIdentifier instanceIdentifier) {
+ if (dataNormalizer == null) {
+ throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible");
+ }
+
+ try {
+ return dataNormalizer.toLegacy(instanceIdentifier);
+ } catch (final DataNormalizationException e) {
+ throw new RestconfDocumentedException("Data normalizer failed. Normalization isn't possible", e);
+ }
+ }
+
+ public boolean isNodeMixin(final YangInstanceIdentifier path) {
+ final DataNormalizationOperation<?> operation;
+ try {
+ operation = dataNormalizer.getOperation(path);
+ } catch (final DataNormalizationException e) {
+ throw new RestconfDocumentedException("Data normalizer failed. Normalization isn't possible", e);
+ }
+ return operation.isMixin();
+ }
+
+ private static EffectiveModelContext getModelContext(final DOMMountPoint mountPoint) {
+ return mountPoint.getService(DOMSchemaService.class)
+ .flatMap(svc -> Optional.ofNullable(svc.getGlobalContext()))
+ .orElse(null);
+ }
+
+ public static final class FoundChild {
+ // Intermediate schema tree children, usually empty
+ public final @NonNull List<QName> intermediate;
+ public final @NonNull DataSchemaNode child;
+
+ private FoundChild(final DataSchemaNode child, final List<QName> intermediate) {
+ this.child = requireNonNull(child);
+ this.intermediate = requireNonNull(intermediate);
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizationException.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizationException.java
new file mode 100644
index 0000000..b9e7214
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizationException.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+final class DataNormalizationException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ DataNormalizationException(final String message) {
+ super(message);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizationOperation.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizationOperation.java
new file mode 100644
index 0000000..eb41c78
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizationOperation.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import static com.google.common.base.Verify.verifyNotNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.common.Empty;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
+import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+abstract class DataNormalizationOperation<T extends PathArgument> implements Identifiable<T> {
+ private final T identifier;
+
+ DataNormalizationOperation(final T identifier) {
+ this.identifier = identifier;
+ }
+
+ static DataNormalizationOperation<?> from(final EffectiveModelContext ctx) {
+ return new ContainerNormalization(ctx);
+ }
+
+ @Override
+ public T getIdentifier() {
+ return identifier;
+ }
+
+ boolean isMixin() {
+ return false;
+ }
+
+ Set<QName> getQNameIdentifiers() {
+ return ImmutableSet.of(identifier.getNodeType());
+ }
+
+ abstract DataNormalizationOperation<?> getChild(PathArgument child) throws DataNormalizationException;
+
+ abstract DataNormalizationOperation<?> getChild(QName child) throws DataNormalizationException;
+
+ abstract DataNormalizationOperation<?> enterChild(QName child, SchemaInferenceStack stack)
+ throws DataNormalizationException;
+
+ abstract DataNormalizationOperation<?> enterChild(PathArgument child, SchemaInferenceStack stack)
+ throws DataNormalizationException;
+
+ void pushToStack(final SchemaInferenceStack stack) {
+ // Accurate for most subclasses
+ stack.enterSchemaTree(getIdentifier().getNodeType());
+ }
+
+ private abstract static class SimpleTypeNormalization<T extends PathArgument>
+ extends DataNormalizationOperation<T> {
+ SimpleTypeNormalization(final T identifier) {
+ super(identifier);
+ }
+
+ @Override
+ final DataNormalizationOperation<?> getChild(final PathArgument child) {
+ return null;
+ }
+
+ @Override
+ final DataNormalizationOperation<?> getChild(final QName child) {
+ return null;
+ }
+
+ @Override
+ final DataNormalizationOperation<?> enterChild(final QName child, final SchemaInferenceStack stack) {
+ return null;
+ }
+
+ @Override
+ final DataNormalizationOperation<?> enterChild(final PathArgument child, final SchemaInferenceStack stack) {
+ return null;
+ }
+ }
+
+ private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
+ LeafNormalization(final LeafSchemaNode potential) {
+ super(new NodeIdentifier(potential.getQName()));
+ }
+ }
+
+ private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
+ LeafListEntryNormalization(final LeafListSchemaNode potential) {
+ super(new NodeWithValue<>(potential.getQName(), Empty.value()));
+ }
+
+ @Override
+ protected void pushToStack(final SchemaInferenceStack stack) {
+ // No-op
+ }
+ }
+
+ private abstract static class DataContainerNormalizationOperation<T extends PathArgument>
+ extends DataNormalizationOperation<T> {
+ private final DataNodeContainer schema;
+ private final Map<QName, DataNormalizationOperation<?>> byQName = new ConcurrentHashMap<>();
+ private final Map<PathArgument, DataNormalizationOperation<?>> byArg = new ConcurrentHashMap<>();
+
+ DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
+ super(identifier);
+ this.schema = schema;
+ }
+
+ @Override
+ DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException {
+ DataNormalizationOperation<?> potential = byArg.get(child);
+ if (potential != null) {
+ return potential;
+ }
+ potential = fromLocalSchema(child);
+ return register(potential);
+ }
+
+ @Override
+ DataNormalizationOperation<?> getChild(final QName child) throws DataNormalizationException {
+ DataNormalizationOperation<?> potential = byQName.get(child);
+ if (potential != null) {
+ return potential;
+ }
+ potential = fromLocalSchemaAndQName(schema, child);
+ return register(potential);
+ }
+
+ @Override
+ final DataNormalizationOperation<?> enterChild(final QName child, final SchemaInferenceStack stack)
+ throws DataNormalizationException {
+ return pushToStack(getChild(child), stack);
+ }
+
+ @Override
+ final DataNormalizationOperation<?> enterChild(final PathArgument child, final SchemaInferenceStack stack)
+ throws DataNormalizationException {
+ return pushToStack(getChild(child), stack);
+ }
+
+ private static DataNormalizationOperation<?> pushToStack(final DataNormalizationOperation<?> child,
+ final SchemaInferenceStack stack) {
+ if (child != null) {
+ child.pushToStack(stack);
+ }
+ return child;
+ }
+
+ private DataNormalizationOperation<?> fromLocalSchema(final PathArgument child)
+ throws DataNormalizationException {
+ if (child instanceof AugmentationIdentifier) {
+ return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
+ .iterator().next());
+ }
+ return fromSchemaAndQNameChecked(schema, child.getNodeType());
+ }
+
+ DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema2,
+ final QName child) throws DataNormalizationException {
+ return fromSchemaAndQNameChecked(schema2, child);
+ }
+
+ private DataNormalizationOperation<?> register(final DataNormalizationOperation<?> potential) {
+ if (potential != null) {
+ byArg.put(potential.getIdentifier(), potential);
+ for (final QName qname : potential.getQNameIdentifiers()) {
+ byQName.put(qname, potential);
+ }
+ }
+ return potential;
+ }
+
+ private static DataNormalizationOperation<?> fromSchemaAndQNameChecked(final DataNodeContainer schema,
+ final QName child) throws DataNormalizationException {
+
+ final DataSchemaNode result = findChildSchemaNode(schema, child);
+ if (result == null) {
+ throw new DataNormalizationException(String.format(
+ "Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child,
+ schema,schema.getChildNodes()));
+ }
+
+ // We try to look up if this node was added by augmentation
+ if (schema instanceof DataSchemaNode && result.isAugmenting()) {
+ return fromAugmentation(schema, (AugmentationTarget) schema, result);
+ }
+ return fromDataSchemaNode(result);
+ }
+ }
+
+ private static final class ListItemNormalization extends
+ DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
+ ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
+ super(identifier, schema);
+ }
+
+ @Override
+ protected void pushToStack(final SchemaInferenceStack stack) {
+ // No-op
+ }
+ }
+
+ private static final class UnkeyedListItemNormalization
+ extends DataContainerNormalizationOperation<NodeIdentifier> {
+ UnkeyedListItemNormalization(final ListSchemaNode schema) {
+ super(new NodeIdentifier(schema.getQName()), schema);
+ }
+
+ @Override
+ protected void pushToStack(final SchemaInferenceStack stack) {
+ // No-op
+ }
+ }
+
+ private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
+ ContainerNormalization(final ContainerLike schema) {
+ super(new NodeIdentifier(schema.getQName()), schema);
+ }
+ }
+
+ private abstract static class MixinNormalizationOp<T extends PathArgument> extends DataNormalizationOperation<T> {
+ MixinNormalizationOp(final T identifier) {
+ super(identifier);
+ }
+
+ @Override
+ final boolean isMixin() {
+ return true;
+ }
+ }
+
+ private abstract static class ListLikeNormalizationOp<T extends PathArgument> extends MixinNormalizationOp<T> {
+ ListLikeNormalizationOp(final T identifier) {
+ super(identifier);
+ }
+
+ @Override
+ protected final DataNormalizationOperation<?> enterChild(final QName child, final SchemaInferenceStack stack)
+ throws DataNormalizationException {
+ // Stack is already pointing to the corresponding statement, now we are just working with the child
+ return getChild(child);
+ }
+
+ @Override
+ protected final DataNormalizationOperation<?> enterChild(final PathArgument child,
+ final SchemaInferenceStack stack) throws DataNormalizationException {
+ return getChild(child);
+ }
+ }
+
+ private static final class LeafListMixinNormalization extends ListLikeNormalizationOp<NodeIdentifier> {
+ private final DataNormalizationOperation<?> innerOp;
+
+ LeafListMixinNormalization(final LeafListSchemaNode potential) {
+ super(new NodeIdentifier(potential.getQName()));
+ innerOp = new LeafListEntryNormalization(potential);
+ }
+
+ @Override
+ DataNormalizationOperation<?> getChild(final PathArgument child) {
+ if (child instanceof NodeWithValue) {
+ return innerOp;
+ }
+ return null;
+ }
+
+ @Override
+ DataNormalizationOperation<?> getChild(final QName child) {
+ if (getIdentifier().getNodeType().equals(child)) {
+ return innerOp;
+ }
+ return null;
+ }
+ }
+
+ private static final class AugmentationNormalization
+ extends DataContainerNormalizationOperation<AugmentationIdentifier> {
+
+ AugmentationNormalization(final AugmentationSchemaNode augmentation, final DataNodeContainer schema) {
+ super(DataSchemaContextNode.augmentationIdentifierFrom(augmentation),
+ new EffectiveAugmentationSchema(augmentation, schema));
+ }
+
+ @Override
+ boolean isMixin() {
+ return true;
+ }
+
+ @Override
+ DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema, final QName child) {
+ final DataSchemaNode result = findChildSchemaNode(schema, child);
+ if (result == null) {
+ return null;
+ }
+
+ // We try to look up if this node was added by augmentation
+ if (schema instanceof DataSchemaNode && result.isAugmenting()) {
+ return fromAugmentation(schema, (AugmentationTarget) schema, result);
+ }
+ return fromDataSchemaNode(result);
+ }
+
+ @Override
+ Set<QName> getQNameIdentifiers() {
+ return getIdentifier().getPossibleChildNames();
+ }
+
+ @Override
+ void pushToStack(final SchemaInferenceStack stack) {
+ // No-op
+ }
+ }
+
+ private static final class MapMixinNormalization extends ListLikeNormalizationOp<NodeIdentifier> {
+ private final ListItemNormalization innerNode;
+
+ MapMixinNormalization(final ListSchemaNode list) {
+ super(new NodeIdentifier(list.getQName()));
+ innerNode = new ListItemNormalization(NodeIdentifierWithPredicates.of(list.getQName()), list);
+ }
+
+ @Override
+ DataNormalizationOperation<?> getChild(final PathArgument child) {
+ if (child.getNodeType().equals(getIdentifier().getNodeType())) {
+ return innerNode;
+ }
+ return null;
+ }
+
+ @Override
+ DataNormalizationOperation<?> getChild(final QName child) {
+ if (getIdentifier().getNodeType().equals(child)) {
+ return innerNode;
+ }
+ return null;
+ }
+ }
+
+ private static final class UnkeyedListMixinNormalization extends ListLikeNormalizationOp<NodeIdentifier> {
+ private final UnkeyedListItemNormalization innerNode;
+
+ UnkeyedListMixinNormalization(final ListSchemaNode list) {
+ super(new NodeIdentifier(list.getQName()));
+ innerNode = new UnkeyedListItemNormalization(list);
+ }
+
+ @Override
+ DataNormalizationOperation<?> getChild(final PathArgument child) {
+ if (child.getNodeType().equals(getIdentifier().getNodeType())) {
+ return innerNode;
+ }
+ return null;
+ }
+
+ @Override
+ DataNormalizationOperation<?> getChild(final QName child) {
+ if (getIdentifier().getNodeType().equals(child)) {
+ return innerNode;
+ }
+ return null;
+ }
+ }
+
+ private static final class ChoiceNodeNormalization extends MixinNormalizationOp<NodeIdentifier> {
+ private final ImmutableMap<QName, DataNormalizationOperation<?>> byQName;
+ private final ImmutableMap<PathArgument, DataNormalizationOperation<?>> byArg;
+ private final ImmutableMap<DataNormalizationOperation<?>, QName> childToCase;
+
+ ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
+ super(new NodeIdentifier(schema.getQName()));
+ ImmutableMap.Builder<DataNormalizationOperation<?>, QName> childToCaseBuilder = ImmutableMap.builder();
+ final ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
+ final ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder =
+ ImmutableMap.builder();
+
+ for (final CaseSchemaNode caze : schema.getCases()) {
+ for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
+ final DataNormalizationOperation<?> childOp = fromDataSchemaNode(cazeChild);
+ byArgBuilder.put(childOp.getIdentifier(), childOp);
+ childToCaseBuilder.put(childOp, caze.getQName());
+ for (final QName qname : childOp.getQNameIdentifiers()) {
+ byQNameBuilder.put(qname, childOp);
+ }
+ }
+ }
+ childToCase = childToCaseBuilder.build();
+ byQName = byQNameBuilder.build();
+ byArg = byArgBuilder.build();
+ }
+
+ @Override
+ DataNormalizationOperation<?> getChild(final PathArgument child) {
+ return byArg.get(child);
+ }
+
+ @Override
+ DataNormalizationOperation<?> getChild(final QName child) {
+ return byQName.get(child);
+ }
+
+ @Override
+ Set<QName> getQNameIdentifiers() {
+ return byQName.keySet();
+ }
+
+ @Override
+ DataNormalizationOperation<?> enterChild(final QName child, final SchemaInferenceStack stack) {
+ return pushToStack(getChild(child), stack);
+ }
+
+ @Override
+ DataNormalizationOperation<?> enterChild(final PathArgument child, final SchemaInferenceStack stack) {
+ return pushToStack(getChild(child), stack);
+ }
+
+ @Override
+ void pushToStack(final SchemaInferenceStack stack) {
+ stack.enterChoice(getIdentifier().getNodeType());
+ }
+
+ private DataNormalizationOperation<?> pushToStack(final DataNormalizationOperation<?> child,
+ final SchemaInferenceStack stack) {
+ if (child != null) {
+ final var caseName = verifyNotNull(childToCase.get(child), "No case statement for %s in %s", child,
+ this);
+ stack.enterSchemaTree(caseName);
+ child.pushToStack(stack);
+ }
+ return child;
+ }
+ }
+
+ private static final class AnyxmlNormalization extends SimpleTypeNormalization<NodeIdentifier> {
+ AnyxmlNormalization(final AnyxmlSchemaNode schema) {
+ super(new NodeIdentifier(schema.getQName()));
+ }
+ }
+
+ private static @Nullable DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
+ final DataSchemaNode potential = parent.dataChildByName(child);
+ return potential != null ? potential : findChoice(parent, child);
+ }
+
+ private static @Nullable ChoiceSchemaNode findChoice(final DataNodeContainer parent, final QName child) {
+ for (final ChoiceSchemaNode choice : Iterables.filter(parent.getChildNodes(), ChoiceSchemaNode.class)) {
+ for (final CaseSchemaNode caze : choice.getCases()) {
+ if (findChildSchemaNode(caze, child) != null) {
+ return choice;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a DataNormalizationOperation for provided child node.
+ *
+ * <p>
+ * If supplied child is added by Augmentation this operation returns
+ * a DataNormalizationOperation for augmentation,
+ * otherwise returns a DataNormalizationOperation for child as
+ * call for {@link #fromDataSchemaNode(DataSchemaNode)}.
+ */
+ private static DataNormalizationOperation<?> fromAugmentation(final DataNodeContainer parent,
+ final AugmentationTarget parentAug, final DataSchemaNode child) {
+ for (final AugmentationSchemaNode aug : parentAug.getAvailableAugmentations()) {
+ if (aug.dataChildByName(child.getQName()) != null) {
+ return new AugmentationNormalization(aug, parent);
+ }
+ }
+ return fromDataSchemaNode(child);
+ }
+
+ static DataNormalizationOperation<?> fromDataSchemaNode(final DataSchemaNode potential) {
+ if (potential instanceof ContainerSchemaNode) {
+ return new ContainerNormalization((ContainerSchemaNode) potential);
+ } else if (potential instanceof ListSchemaNode) {
+ return fromListSchemaNode((ListSchemaNode) potential);
+ } else if (potential instanceof LeafSchemaNode) {
+ return new LeafNormalization((LeafSchemaNode) potential);
+ } else if (potential instanceof ChoiceSchemaNode) {
+ return new ChoiceNodeNormalization((ChoiceSchemaNode) potential);
+ } else if (potential instanceof LeafListSchemaNode) {
+ return new LeafListMixinNormalization((LeafListSchemaNode) potential);
+ } else if (potential instanceof AnyxmlSchemaNode) {
+ return new AnyxmlNormalization((AnyxmlSchemaNode) potential);
+ }
+ return null;
+ }
+
+ private static DataNormalizationOperation<?> fromListSchemaNode(final ListSchemaNode potential) {
+ if (potential.getKeyDefinition().isEmpty()) {
+ return new UnkeyedListMixinNormalization(potential);
+ }
+ return new MapMixinNormalization(potential);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizer.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizer.java
new file mode 100644
index 0000000..334a6c7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/DataNormalizer.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+class DataNormalizer {
+ private final DataNormalizationOperation<?> operation;
+ private final EffectiveModelContext context;
+
+ DataNormalizer(final EffectiveModelContext ctx) {
+ context = requireNonNull(ctx);
+ operation = DataNormalizationOperation.from(ctx);
+ }
+
+ Entry<YangInstanceIdentifier, SchemaInferenceStack> toNormalized(final YangInstanceIdentifier legacy) {
+ List<PathArgument> normalizedArgs = new ArrayList<>();
+
+ DataNormalizationOperation<?> currentOp = operation;
+ Iterator<PathArgument> arguments = legacy.getPathArguments().iterator();
+ SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+
+ try {
+ while (arguments.hasNext()) {
+ PathArgument legacyArg = arguments.next();
+ currentOp = currentOp.enterChild(legacyArg, stack);
+ checkArgument(currentOp != null,
+ "Legacy Instance Identifier %s is not correct. Normalized Instance Identifier so far %s",
+ legacy, normalizedArgs);
+ while (currentOp.isMixin()) {
+ normalizedArgs.add(currentOp.getIdentifier());
+ currentOp = currentOp.enterChild(legacyArg.getNodeType(), stack);
+ }
+ normalizedArgs.add(legacyArg);
+ }
+ } catch (DataNormalizationException e) {
+ throw new IllegalArgumentException("Failed to normalize path " + legacy, e);
+ }
+
+ return Map.entry(YangInstanceIdentifier.create(normalizedArgs), stack);
+ }
+
+ DataNormalizationOperation<?> getOperation(final YangInstanceIdentifier legacy)
+ throws DataNormalizationException {
+ DataNormalizationOperation<?> currentOp = operation;
+
+ for (PathArgument pathArgument : legacy.getPathArguments()) {
+ currentOp = currentOp.getChild(pathArgument);
+ }
+ return currentOp;
+ }
+
+ YangInstanceIdentifier toLegacy(final YangInstanceIdentifier normalized) throws DataNormalizationException {
+ ImmutableList.Builder<PathArgument> legacyArgs = ImmutableList.builder();
+ DataNormalizationOperation<?> currentOp = operation;
+ for (PathArgument normalizedArg : normalized.getPathArguments()) {
+ currentOp = currentOp.getChild(normalizedArg);
+ if (!currentOp.isMixin()) {
+ legacyArgs.add(normalizedArg);
+ }
+ }
+ return YangInstanceIdentifier.create(legacyArgs.build());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/JSONRestconfServiceImpl.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/JSONRestconfServiceImpl.java
new file mode 100644
index 0000000..296fd91
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/JSONRestconfServiceImpl.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.JsonToPatchBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.PatchJsonBodyWriter;
+import org.opendaylight.netconf.sal.restconf.api.JSONRestconfService;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.restconf.common.util.SimpleUriInfo;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.OperationFailedException;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of the JSONRestconfService interface using the restconf Draft02 implementation.
+ *
+ * @author Thomas Pantelis
+ * @deprecated Replaced by {JSONRestconfServiceRfc8040Impl from restconf-nb-rfc8040
+ */
+@Singleton
+@Deprecated
+public class JSONRestconfServiceImpl implements JSONRestconfService {
+ private static final Logger LOG = LoggerFactory.getLogger(JSONRestconfServiceImpl.class);
+
+ private static final Annotation[] EMPTY_ANNOTATIONS = new Annotation[0];
+
+ private final ControllerContext controllerContext;
+ private final RestconfService restconfService;
+
+ @Inject
+ public JSONRestconfServiceImpl(final ControllerContext controllerContext, final RestconfImpl restconfService) {
+ this.controllerContext = controllerContext;
+ this.restconfService = restconfService;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public void put(final String uriPath, final String payload) throws OperationFailedException {
+ requireNonNull(payload, "payload can't be null");
+
+ LOG.debug("put: uriPath: {}, payload: {}", uriPath, payload);
+
+ final InputStream entityStream = new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8));
+ final NormalizedNodeContext context = JsonNormalizedNodeBodyReader.readFrom(uriPath, entityStream, false,
+ controllerContext);
+
+ LOG.debug("Parsed YangInstanceIdentifier: {}", context.getInstanceIdentifierContext().getInstanceIdentifier());
+ LOG.debug("Parsed NormalizedNode: {}", context.getData());
+
+ try {
+ restconfService.updateConfigurationData(uriPath, context, new SimpleUriInfo(uriPath));
+ } catch (final Exception e) {
+ propagateExceptionAs(uriPath, e, "PUT");
+ }
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public void post(final String uriPath, final String payload) throws OperationFailedException {
+ requireNonNull(payload, "payload can't be null");
+
+ LOG.debug("post: uriPath: {}, payload: {}", uriPath, payload);
+
+ final InputStream entityStream = new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8));
+ final NormalizedNodeContext context = JsonNormalizedNodeBodyReader.readFrom(uriPath, entityStream, true,
+ controllerContext);
+
+ LOG.debug("Parsed YangInstanceIdentifier: {}", context.getInstanceIdentifierContext().getInstanceIdentifier());
+ LOG.debug("Parsed NormalizedNode: {}", context.getData());
+
+ try {
+ restconfService.createConfigurationData(uriPath, context, new SimpleUriInfo(uriPath));
+ } catch (final Exception e) {
+ propagateExceptionAs(uriPath, e, "POST");
+ }
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public void delete(final String uriPath) throws OperationFailedException {
+ LOG.debug("delete: uriPath: {}", uriPath);
+
+ try {
+ restconfService.deleteConfigurationData(uriPath);
+ } catch (final Exception e) {
+ propagateExceptionAs(uriPath, e, "DELETE");
+ }
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public Optional<String> get(final String uriPath, final LogicalDatastoreType datastoreType)
+ throws OperationFailedException {
+ LOG.debug("get: uriPath: {}", uriPath);
+
+ try {
+ NormalizedNodeContext readData;
+ final SimpleUriInfo uriInfo = new SimpleUriInfo(uriPath);
+ if (datastoreType == LogicalDatastoreType.CONFIGURATION) {
+ readData = restconfService.readConfigurationData(uriPath, uriInfo);
+ } else {
+ readData = restconfService.readOperationalData(uriPath, uriInfo);
+ }
+
+ final Optional<String> result = Optional.of(toJson(readData));
+
+ LOG.debug("get returning: {}", result.get());
+
+ return result;
+ } catch (final Exception e) {
+ if (!isDataMissing(e)) {
+ propagateExceptionAs(uriPath, e, "GET");
+ }
+
+ LOG.debug("Data missing - returning absent");
+ return Optional.empty();
+ }
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF", justification = "Unrecognised NullableDecl")
+ @Override
+ public Optional<String> invokeRpc(final String uriPath, final Optional<String> input)
+ throws OperationFailedException {
+ requireNonNull(uriPath, "uriPath can't be null");
+
+ final String actualInput = input.isPresent() ? input.get() : null;
+
+ LOG.debug("invokeRpc: uriPath: {}, input: {}", uriPath, actualInput);
+
+ String output = null;
+ try {
+ NormalizedNodeContext outputContext;
+ if (actualInput != null) {
+ final InputStream entityStream = new ByteArrayInputStream(actualInput.getBytes(StandardCharsets.UTF_8));
+ final NormalizedNodeContext inputContext =
+ JsonNormalizedNodeBodyReader.readFrom(uriPath, entityStream, true, controllerContext);
+
+ LOG.debug("Parsed YangInstanceIdentifier: {}", inputContext.getInstanceIdentifierContext()
+ .getInstanceIdentifier());
+ LOG.debug("Parsed NormalizedNode: {}", inputContext.getData());
+
+ outputContext = restconfService.invokeRpc(uriPath, inputContext, null);
+ } else {
+ outputContext = restconfService.invokeRpc(uriPath, null, null);
+ }
+
+ if (outputContext.getData() != null) {
+ output = toJson(outputContext);
+ }
+ } catch (final RuntimeException | IOException e) {
+ propagateExceptionAs(uriPath, e, "RPC");
+ }
+
+ return Optional.ofNullable(output);
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public Optional<String> patch(final String uriPath, final String payload)
+ throws OperationFailedException {
+
+ String output = null;
+ requireNonNull(payload, "payload can't be null");
+
+ LOG.debug("patch: uriPath: {}, payload: {}", uriPath, payload);
+
+ final InputStream entityStream = new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8));
+
+ JsonToPatchBodyReader jsonToPatchBodyReader = new JsonToPatchBodyReader(controllerContext);
+ final PatchContext context = jsonToPatchBodyReader.readFrom(uriPath, entityStream);
+
+ LOG.debug("Parsed YangInstanceIdentifier: {}", context.getInstanceIdentifierContext().getInstanceIdentifier());
+ LOG.debug("Parsed NormalizedNode: {}", context.getData());
+
+ try {
+ PatchStatusContext patchStatusContext = restconfService
+ .patchConfigurationData(context, new SimpleUriInfo(uriPath));
+ output = toJson(patchStatusContext);
+ } catch (final Exception e) {
+ propagateExceptionAs(uriPath, e, "PATCH");
+ }
+ return Optional.ofNullable(output);
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public Optional<String> subscribeToStream(final String identifier, final MultivaluedMap<String, String> params)
+ throws OperationFailedException {
+ //Note: We use http://127.0.0.1 because the Uri parser requires something there though it does nothing
+ String uri = new StringBuilder("http://127.0.0.1:8081/restconf/streams/stream/").append(identifier).toString();
+ MultivaluedMap queryParams = params != null ? params : new MultivaluedHashMap<String, String>();
+ UriInfo uriInfo = new SimpleUriInfo(uri, queryParams);
+
+ String jsonRes = null;
+ try {
+ NormalizedNodeContext res = restconfService.subscribeToStream(identifier, uriInfo);
+ jsonRes = toJson(res);
+ } catch (final Exception e) {
+ propagateExceptionAs(identifier, e, "RPC");
+ }
+
+ return Optional.ofNullable(jsonRes);
+ }
+
+ private static String toJson(final PatchStatusContext patchStatusContext) throws IOException {
+ final PatchJsonBodyWriter writer = new PatchJsonBodyWriter();
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ writer.writeTo(patchStatusContext, PatchStatusContext.class, null, EMPTY_ANNOTATIONS,
+ MediaType.APPLICATION_JSON_TYPE, null, outputStream);
+ return outputStream.toString(StandardCharsets.UTF_8);
+ }
+
+ private static String toJson(final NormalizedNodeContext readData) throws IOException {
+ final NormalizedNodeJsonBodyWriter writer = new NormalizedNodeJsonBodyWriter();
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ writer.writeTo(readData, NormalizedNodeContext.class, null, EMPTY_ANNOTATIONS,
+ MediaType.APPLICATION_JSON_TYPE, null, outputStream);
+ return outputStream.toString(StandardCharsets.UTF_8);
+ }
+
+ private static boolean isDataMissing(final Exception exception) {
+ boolean dataMissing = false;
+ if (exception instanceof RestconfDocumentedException) {
+ final RestconfDocumentedException rde = (RestconfDocumentedException)exception;
+ if (!rde.getErrors().isEmpty()) {
+ if (rde.getErrors().get(0).getErrorTag() == ErrorTag.DATA_MISSING) {
+ dataMissing = true;
+ }
+ }
+ }
+
+ return dataMissing;
+ }
+
+ private static void propagateExceptionAs(final String uriPath, final Exception exception, final String operation)
+ throws OperationFailedException {
+ LOG.debug("Error for uriPath: {}", uriPath, exception);
+
+ if (exception instanceof RestconfDocumentedException) {
+ throw new OperationFailedException(String.format(
+ "%s failed for URI %s", operation, uriPath), exception.getCause(),
+ toRpcErrors(((RestconfDocumentedException)exception).getErrors()));
+ }
+
+ throw new OperationFailedException(String.format("%s failed for URI %s", operation, uriPath), exception);
+ }
+
+ private static RpcError[] toRpcErrors(final List<RestconfError> from) {
+ final RpcError[] to = new RpcError[from.size()];
+ int index = 0;
+ for (final RestconfError e: from) {
+ to[index++] = RpcResultBuilder.newError(e.getErrorType(), e.getErrorTag(), e.getErrorMessage());
+ }
+
+ return to;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/NormalizedDataPrunner.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/NormalizedDataPrunner.java
new file mode 100644
index 0000000..975da60
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/NormalizedDataPrunner.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyxmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MixinNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UserMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+
+class NormalizedDataPrunner {
+
+ public DataContainerChild pruneDataAtDepth(final DataContainerChild node, final Integer depth) {
+ if (depth == null) {
+ return node;
+ }
+
+ if (node instanceof LeafNode || node instanceof LeafSetNode || node instanceof AnyxmlNode) {
+ return node;
+ } else if (node instanceof MixinNode) {
+ return processMixinNode(node, depth);
+ } else if (node instanceof DataContainerNode) {
+ return processContainerNode(node, depth);
+ }
+ throw new IllegalStateException("Unexpected Mixin node occured why pruning data to requested depth");
+ }
+
+ private DataContainerChild processMixinNode(final NormalizedNode node, final Integer depth) {
+ if (node instanceof AugmentationNode) {
+ return processAugmentationNode(node, depth);
+ } else if (node instanceof ChoiceNode) {
+ return processChoiceNode(node, depth);
+ } else if (node instanceof UserMapNode) {
+ return processOrderedMapNode(node, depth);
+ } else if (node instanceof MapNode) {
+ return processMapNode(node, depth);
+ } else if (node instanceof UnkeyedListNode) {
+ return processUnkeyedListNode(node, depth);
+ }
+ throw new IllegalStateException("Unexpected Mixin node occured why pruning data to requested depth");
+ }
+
+ private DataContainerChild processContainerNode(final NormalizedNode node, final Integer depth) {
+ final ContainerNode containerNode = (ContainerNode) node;
+ DataContainerNodeBuilder<NodeIdentifier, ContainerNode> newContainerBuilder = Builders.containerBuilder()
+ .withNodeIdentifier(containerNode.getIdentifier());
+ if (depth > 1) {
+ processDataContainerChild((DataContainerNode) node, depth, newContainerBuilder);
+ }
+ return newContainerBuilder.build();
+ }
+
+ private DataContainerChild processChoiceNode(final NormalizedNode node, final Integer depth) {
+ final ChoiceNode choiceNode = (ChoiceNode) node;
+ DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> newChoiceBuilder = Builders.choiceBuilder()
+ .withNodeIdentifier(choiceNode.getIdentifier());
+
+ processDataContainerChild((DataContainerNode) node, depth, newChoiceBuilder);
+
+ return newChoiceBuilder.build();
+ }
+
+ private DataContainerChild processAugmentationNode(final NormalizedNode node, final Integer depth) {
+ final AugmentationNode augmentationNode = (AugmentationNode) node;
+ DataContainerNodeBuilder<AugmentationIdentifier, ? extends DataContainerChild> newAugmentationBuilder =
+ Builders.augmentationBuilder().withNodeIdentifier(augmentationNode.getIdentifier());
+
+ processDataContainerChild((DataContainerNode) node, depth, newAugmentationBuilder);
+
+ return newAugmentationBuilder.build();
+ }
+
+ private void processDataContainerChild(final DataContainerNode node, final Integer depth,
+ final DataContainerNodeBuilder<?, ?> newBuilder) {
+ for (DataContainerChild nodeValue : node.body()) {
+ newBuilder.withChild(pruneDataAtDepth(nodeValue, depth - 1));
+ }
+ }
+
+ private DataContainerChild processUnkeyedListNode(final NormalizedNode node, final Integer depth) {
+ CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> newUnkeyedListBuilder = Builders
+ .unkeyedListBuilder();
+ if (depth > 1) {
+ for (UnkeyedListEntryNode oldUnkeyedListEntry : ((UnkeyedListNode) node).body()) {
+ DataContainerNodeBuilder<NodeIdentifier, UnkeyedListEntryNode> newUnkeyedListEntry = Builders
+ .unkeyedListEntryBuilder().withNodeIdentifier(oldUnkeyedListEntry.getIdentifier());
+ for (DataContainerChild oldUnkeyedListEntryValue : oldUnkeyedListEntry.body()) {
+ newUnkeyedListEntry.withChild(pruneDataAtDepth(oldUnkeyedListEntryValue, depth - 1));
+ }
+ newUnkeyedListBuilder.addChild(newUnkeyedListEntry.build());
+ }
+ }
+ return newUnkeyedListBuilder.build();
+ }
+
+ private DataContainerChild processOrderedMapNode(final NormalizedNode node, final Integer depth) {
+ CollectionNodeBuilder<MapEntryNode, UserMapNode> newOrderedMapNodeBuilder = Builders.orderedMapBuilder();
+ processMapEntries(node, depth, newOrderedMapNodeBuilder);
+ return newOrderedMapNodeBuilder.build();
+ }
+
+ private DataContainerChild processMapNode(final NormalizedNode node, final Integer depth) {
+ CollectionNodeBuilder<MapEntryNode, SystemMapNode> newMapNodeBuilder = Builders.mapBuilder();
+ processMapEntries(node, depth, newMapNodeBuilder);
+ return newMapNodeBuilder.build();
+ }
+
+ private void processMapEntries(final NormalizedNode node, final Integer depth,
+ final CollectionNodeBuilder<MapEntryNode, ? extends MapNode> newOrderedMapNodeBuilder) {
+ if (depth > 1) {
+ for (MapEntryNode oldMapEntryNode : ((MapNode) node).body()) {
+ DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> newMapEntryNodeBuilder =
+ Builders.mapEntryBuilder().withNodeIdentifier(oldMapEntryNode.getIdentifier());
+ for (DataContainerChild mapEntryNodeValue : oldMapEntryNode.body()) {
+ newMapEntryNodeBuilder.withChild(pruneDataAtDepth(mapEntryNodeValue, depth - 1));
+ }
+ newOrderedMapNodeBuilder.withChild(newMapEntryNodeBuilder.build());
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/PutResult.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/PutResult.java
new file mode 100644
index 0000000..87e33b9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/PutResult.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import com.google.common.util.concurrent.FluentFuture;
+import javax.ws.rs.core.Response.Status;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+
+/**
+ * Wrapper for status and future of PUT operation.
+ */
+public class PutResult {
+ private final Status status;
+ private final FluentFuture<? extends CommitInfo> future;
+
+ /**
+ * Wrap status and future by constructor - make this immutable.
+ *
+ * @param status
+ * status of operations
+ * @param future
+ * result of submit of PUT operation
+ */
+ public PutResult(final Status status, final FluentFuture<? extends CommitInfo> future) {
+ this.status = status;
+ this.future = future;
+ }
+
+ /**
+ * Get status.
+ *
+ * @return {@link Status} result
+ */
+ public Status getStatus() {
+ return this.status;
+ }
+
+ /**
+ * Get future.
+ *
+ * @return {@link FluentFuture} result
+ */
+ public FluentFuture<? extends CommitInfo> getFutureOfPutData() {
+ return this.future;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/QueryParametersParser.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/QueryParametersParser.java
new file mode 100644
index 0000000..098c53b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/QueryParametersParser.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import com.google.common.base.Strings;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.netconf.sal.rest.impl.WriterParameters;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+
+public final class QueryParametersParser {
+
+ private enum UriParameters {
+ PRETTY_PRINT("prettyPrint"),
+ DEPTH("depth");
+
+ private final String uriParameterName;
+
+ UriParameters(final String uriParameterName) {
+ this.uriParameterName = uriParameterName;
+ }
+
+ @Override
+ public String toString() {
+ return uriParameterName;
+ }
+ }
+
+ private QueryParametersParser() {
+
+ }
+
+ public static WriterParameters parseWriterParameters(final UriInfo info) {
+ final WriterParameters.WriterParametersBuilder wpBuilder = new WriterParameters.WriterParametersBuilder();
+ if (info == null) {
+ return wpBuilder.build();
+ }
+
+ String param = info.getQueryParameters(false).getFirst(UriParameters.DEPTH.toString());
+ if (!Strings.isNullOrEmpty(param) && !"unbounded".equals(param)) {
+ try {
+ final int depth = Integer.parseInt(param);
+ if (depth < 1) {
+ throw new RestconfDocumentedException(
+ new RestconfError(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ "Invalid depth parameter: " + depth, null,
+ "The depth parameter must be an integer > 1 or \"unbounded\""));
+ }
+ wpBuilder.setDepth(depth);
+ } catch (final NumberFormatException e) {
+ throw new RestconfDocumentedException(e, new RestconfError(
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ "Invalid depth parameter: " + e.getMessage(), null,
+ "The depth parameter must be an integer > 1 or \"unbounded\""));
+ }
+ }
+ param = info.getQueryParameters(false).getFirst(UriParameters.PRETTY_PRINT.toString());
+ wpBuilder.setPrettyPrint("true".equals(param));
+ return wpBuilder.build();
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestCodec.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestCodec.java
new file mode 100644
index 0000000..5d7a840
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestCodec.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.sal.rest.impl.StringModuleInstanceIdentifierCodec;
+import org.opendaylight.restconf.common.util.IdentityValuesDTO;
+import org.opendaylight.restconf.common.util.IdentityValuesDTO.IdentityValue;
+import org.opendaylight.restconf.common.util.IdentityValuesDTO.Predicate;
+import org.opendaylight.restconf.common.util.RestUtil;
+import org.opendaylight.yangtools.concepts.IllegalArgumentCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.codec.IdentityrefCodec;
+import org.opendaylight.yangtools.yang.data.api.codec.InstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.api.codec.LeafrefCodec;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class RestCodec {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RestCodec.class);
+
+ private RestCodec() {
+ }
+
+ // FIXME: IllegalArgumentCodec is not quite accurate
+ public static IllegalArgumentCodec<Object, Object> from(final TypeDefinition<?> typeDefinition,
+ final DOMMountPoint mountPoint, final ControllerContext controllerContext) {
+ return new ObjectCodec(typeDefinition, mountPoint, controllerContext);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static final class ObjectCodec implements IllegalArgumentCodec<Object, Object> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ObjectCodec.class);
+
+ public static final IllegalArgumentCodec LEAFREF_DEFAULT_CODEC = new LeafrefCodecImpl();
+
+ private final ControllerContext controllerContext;
+ private final IllegalArgumentCodec instanceIdentifier;
+ private final IllegalArgumentCodec identityrefCodec;
+
+ private final TypeDefinition<?> type;
+
+ private ObjectCodec(final TypeDefinition<?> typeDefinition, final DOMMountPoint mountPoint,
+ final ControllerContext controllerContext) {
+ this.controllerContext = controllerContext;
+ type = RestUtil.resolveBaseTypeFrom(typeDefinition);
+ if (type instanceof IdentityrefTypeDefinition) {
+ identityrefCodec = new IdentityrefCodecImpl(mountPoint, controllerContext);
+ } else {
+ identityrefCodec = null;
+ }
+ if (type instanceof InstanceIdentifierTypeDefinition) {
+ instanceIdentifier = new InstanceIdentifierCodecImpl(mountPoint, controllerContext);
+ } else {
+ instanceIdentifier = null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ @SuppressFBWarnings(value = "NP_NONNULL_RETURN_VIOLATION", justification = "Legacy code")
+ public Object deserialize(final Object input) {
+ try {
+ if (type instanceof IdentityrefTypeDefinition) {
+ if (input instanceof IdentityValuesDTO) {
+ return identityrefCodec.deserialize(input);
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(
+ "Value is not instance of IdentityrefTypeDefinition but is {}. "
+ + "Therefore NULL is used as translation of - {}",
+ input == null ? "null" : input.getClass(), String.valueOf(input));
+ }
+ // FIXME: this should be a hard error
+ return null;
+ } else if (type instanceof InstanceIdentifierTypeDefinition) {
+ if (input instanceof IdentityValuesDTO) {
+ return instanceIdentifier.deserialize(input);
+ } else {
+ final StringModuleInstanceIdentifierCodec codec = new StringModuleInstanceIdentifierCodec(
+ controllerContext.getGlobalSchema());
+ return codec.deserialize((String) input);
+ }
+ } else {
+ final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec =
+ TypeDefinitionAwareCodec.from(type);
+ if (typeAwarecodec != null) {
+ if (input instanceof IdentityValuesDTO) {
+ return typeAwarecodec.deserialize(((IdentityValuesDTO) input).getOriginValue());
+ }
+ return typeAwarecodec.deserialize(String.valueOf(input));
+ } else {
+ LOG.debug("Codec for type \"{}\" is not implemented yet.", type.getQName().getLocalName());
+ // FIXME: this should be a hard error
+ return null;
+ }
+ }
+ } catch (final ClassCastException e) { // TODO remove this catch when everyone use codecs
+ LOG.error("ClassCastException was thrown when codec is invoked with parameter {}", input, e);
+ // FIXME: this should be a hard error
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ @SuppressFBWarnings(value = "NP_NONNULL_RETURN_VIOLATION", justification = "legacy code")
+ public Object serialize(final Object input) {
+ try {
+ if (type instanceof IdentityrefTypeDefinition) {
+ return identityrefCodec.serialize(input);
+ } else if (type instanceof LeafrefTypeDefinition) {
+ return LEAFREF_DEFAULT_CODEC.serialize(input);
+ } else if (type instanceof InstanceIdentifierTypeDefinition) {
+ return instanceIdentifier.serialize(input);
+ } else {
+ final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec =
+ TypeDefinitionAwareCodec.from(type);
+ if (typeAwarecodec != null) {
+ return typeAwarecodec.serialize(input);
+ } else {
+ LOG.debug("Codec for type \"{}\" is not implemented yet.", type.getQName().getLocalName());
+ return null;
+ }
+ }
+ } catch (final ClassCastException e) {
+ // FIXME: remove this catch when everyone use codecs
+ LOG.error("ClassCastException was thrown when codec is invoked with parameter {}", input, e);
+ // FIXME: this should be a hard error
+ return input;
+ }
+ }
+
+ }
+
+ public static class IdentityrefCodecImpl implements IdentityrefCodec<IdentityValuesDTO> {
+ private static final Logger LOG = LoggerFactory.getLogger(IdentityrefCodecImpl.class);
+
+ private final DOMMountPoint mountPoint;
+ private final ControllerContext controllerContext;
+
+ public IdentityrefCodecImpl(final DOMMountPoint mountPoint, final ControllerContext controllerContext) {
+ this.mountPoint = mountPoint;
+ this.controllerContext = controllerContext;
+ }
+
+ @Override
+ public IdentityValuesDTO serialize(final QName data) {
+ return new IdentityValuesDTO(data.getNamespace().toString(), data.getLocalName(), null, null);
+ }
+
+ @Override
+ @SuppressFBWarnings(value = "NP_NONNULL_RETURN_VIOLATION", justification = "See FIXME below")
+ public QName deserialize(final IdentityValuesDTO data) {
+ final IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
+ final Module module = getModuleByNamespace(valueWithNamespace.getNamespace(), mountPoint,
+ controllerContext);
+ if (module == null) {
+ // FIXME: this should be a hard error
+ LOG.info("Module was not found for namespace {}", valueWithNamespace.getNamespace());
+ LOG.info("Idenetityref will be translated as NULL for data - {}", String.valueOf(valueWithNamespace));
+ return null;
+ }
+
+ return QName.create(module.getNamespace(), module.getRevision(), valueWithNamespace.getValue());
+ }
+ }
+
+ public static class LeafrefCodecImpl implements LeafrefCodec<String> {
+
+ @Override
+ public String serialize(final Object data) {
+ return String.valueOf(data);
+ }
+
+ @Override
+ public Object deserialize(final String data) {
+ return data;
+ }
+
+ }
+
+ public static class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec<IdentityValuesDTO> {
+ private static final Logger LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class);
+
+ private final DOMMountPoint mountPoint;
+ private final ControllerContext controllerContext;
+
+ public InstanceIdentifierCodecImpl(final DOMMountPoint mountPoint,
+ final ControllerContext controllerContext) {
+ this.mountPoint = mountPoint;
+ this.controllerContext = controllerContext;
+ }
+
+ @Override
+ public IdentityValuesDTO serialize(final YangInstanceIdentifier data) {
+ final IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO();
+ for (final PathArgument pathArgument : data.getPathArguments()) {
+ final IdentityValue identityValue = qNameToIdentityValue(pathArgument.getNodeType());
+ if (pathArgument instanceof NodeIdentifierWithPredicates && identityValue != null) {
+ final List<Predicate> predicates =
+ keyValuesToPredicateList(((NodeIdentifierWithPredicates) pathArgument).entrySet());
+ identityValue.setPredicates(predicates);
+ } else if (pathArgument instanceof NodeWithValue && identityValue != null) {
+ final List<Predicate> predicates = new ArrayList<>();
+ final String value = String.valueOf(((NodeWithValue<?>) pathArgument).getValue());
+ predicates.add(new Predicate(null, value));
+ identityValue.setPredicates(predicates);
+ }
+ identityValuesDTO.add(identityValue);
+ }
+ return identityValuesDTO;
+ }
+
+ @SuppressFBWarnings(value = { "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", "NP_NONNULL_RETURN_VIOLATION" },
+ justification = "Unrecognised NullableDecl")
+ @Override
+ public YangInstanceIdentifier deserialize(final IdentityValuesDTO data) {
+ final List<PathArgument> result = new ArrayList<>();
+ final IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
+ final Module module = getModuleByNamespace(valueWithNamespace.getNamespace(), mountPoint,
+ controllerContext);
+ if (module == null) {
+ LOG.info("Module by namespace '{}' of first node in instance-identifier was not found.",
+ valueWithNamespace.getNamespace());
+ LOG.info("Instance-identifier will be translated as NULL for data - {}",
+ String.valueOf(valueWithNamespace.getValue()));
+ // FIXME: this should be a hard error
+ return null;
+ }
+
+ DataNodeContainer parentContainer = module;
+ final List<IdentityValue> identities = data.getValuesWithNamespaces();
+ for (int i = 0; i < identities.size(); i++) {
+ final IdentityValue identityValue = identities.get(i);
+ XMLNamespace validNamespace = resolveValidNamespace(identityValue.getNamespace(), mountPoint,
+ controllerContext);
+ final var found = ControllerContext.findInstanceDataChildByNameAndNamespace(
+ parentContainer, identityValue.getValue(), validNamespace);
+ if (found == null) {
+ LOG.info("'{}' node was not found in {}", identityValue, parentContainer.getChildNodes());
+ LOG.info("Instance-identifier will be translated as NULL for data - {}",
+ String.valueOf(identityValue.getValue()));
+ // FIXME: this should be a hard error
+ return null;
+ }
+ final DataSchemaNode node = found.child;
+ final QName qName = node.getQName();
+ PathArgument pathArgument = null;
+ if (identityValue.getPredicates().isEmpty()) {
+ pathArgument = new NodeIdentifier(qName);
+ } else {
+ if (node instanceof LeafListSchemaNode) { // predicate is value of leaf-list entry
+ final Predicate leafListPredicate = identityValue.getPredicates().get(0);
+ if (!leafListPredicate.isLeafList()) {
+ LOG.info("Predicate's data is not type of leaf-list. It should be in format \".='value'\"");
+ LOG.info("Instance-identifier will be translated as NULL for data - {}",
+ String.valueOf(identityValue.getValue()));
+ // FIXME: this should be a hard error
+ return null;
+ }
+ pathArgument = new NodeWithValue<>(qName, leafListPredicate.getValue());
+ } else if (node instanceof ListSchemaNode) { // predicates are keys of list
+ final DataNodeContainer listNode = (DataNodeContainer) node;
+ final Map<QName, Object> predicatesMap = new HashMap<>();
+ for (final Predicate predicate : identityValue.getPredicates()) {
+ validNamespace = resolveValidNamespace(predicate.getName().getNamespace(), mountPoint,
+ controllerContext);
+ final var listKey = ControllerContext
+ .findInstanceDataChildByNameAndNamespace(listNode, predicate.getName().getValue(),
+ validNamespace);
+ predicatesMap.put(listKey.child.getQName(), predicate.getValue());
+ }
+ pathArgument = NodeIdentifierWithPredicates.of(qName, predicatesMap);
+ } else {
+ LOG.info("Node {} is not List or Leaf-list.", node);
+ LOG.info("Instance-identifier will be translated as NULL for data - {}",
+ String.valueOf(identityValue.getValue()));
+ // FIXME: this should be a hard error
+ return null;
+ }
+ }
+ result.add(pathArgument);
+ if (i < identities.size() - 1) { // last element in instance-identifier can be other than
+ // DataNodeContainer
+ if (node instanceof DataNodeContainer) {
+ parentContainer = (DataNodeContainer) node;
+ } else {
+ LOG.info("Node {} isn't instance of DataNodeContainer", node);
+ LOG.info("Instance-identifier will be translated as NULL for data - {}",
+ String.valueOf(identityValue.getValue()));
+ // FIXME: this should be a hard error
+ return null;
+ }
+ }
+ }
+
+ return result.isEmpty() ? null : YangInstanceIdentifier.create(result);
+ }
+
+ private static List<Predicate> keyValuesToPredicateList(final Set<Entry<QName, Object>> keyValues) {
+ final List<Predicate> result = new ArrayList<>();
+ for (final Entry<QName, Object> entry : keyValues) {
+ final QName qualifiedName = entry.getKey();
+ final Object value = entry.getValue();
+ result.add(new Predicate(qNameToIdentityValue(qualifiedName), String.valueOf(value)));
+ }
+ return result;
+ }
+
+ private static IdentityValue qNameToIdentityValue(final QName qualifiedName) {
+ if (qualifiedName != null) {
+ return new IdentityValue(qualifiedName.getNamespace().toString(), qualifiedName.getLocalName());
+ }
+ return null;
+ }
+ }
+
+ private static Module getModuleByNamespace(final String namespace, final DOMMountPoint mountPoint,
+ final ControllerContext controllerContext) {
+ final XMLNamespace validNamespace = resolveValidNamespace(namespace, mountPoint, controllerContext);
+
+ Module module = null;
+ if (mountPoint != null) {
+ module = ControllerContext.findModuleByNamespace(mountPoint, validNamespace);
+ } else {
+ module = controllerContext.findModuleByNamespace(validNamespace);
+ }
+ if (module == null) {
+ LOG.info("Module for namespace {} was not found.", validNamespace);
+ return null;
+ }
+ return module;
+ }
+
+ private static XMLNamespace resolveValidNamespace(final String namespace, final DOMMountPoint mountPoint,
+ final ControllerContext controllerContext) {
+ XMLNamespace validNamespace;
+ if (mountPoint != null) {
+ validNamespace = ControllerContext.findNamespaceByModuleName(mountPoint, namespace);
+ } else {
+ validNamespace = controllerContext.findNamespaceByModuleName(namespace);
+ }
+ if (validNamespace == null) {
+ validNamespace = XMLNamespace.of(namespace);
+ }
+
+ return validNamespace;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java
new file mode 100644
index 0000000..b3a1a9c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java
@@ -0,0 +1,1546 @@
+/*
+ * Copyright (c) 2014 - 2016 Brocade Communication Systems, Inc., Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Predicates;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.net.URI;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.OptimisticLockFailedException;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext.FoundChild;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.netconf.sal.streams.websockets.WebSocketServer;
+import org.opendaylight.restconf.common.OperationsContent;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.restconf.common.util.OperationsResourceUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.CreateDataChangeEventSubscriptionInput1.Scope;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.common.Empty;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.data.tree.api.ModifiedNodeDoesNotExistException;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public final class RestconfImpl implements RestconfService {
+ /**
+ * Notifications are served on port 8181.
+ */
+ private static final int NOTIFICATION_PORT = 8181;
+
+ private static final int CHAR_NOT_FOUND = -1;
+
+ private static final String SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
+
+ private static final Logger LOG = LoggerFactory.getLogger(RestconfImpl.class);
+
+ private static final LogicalDatastoreType DEFAULT_DATASTORE = LogicalDatastoreType.CONFIGURATION;
+
+ private static final XMLNamespace NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT =
+ XMLNamespace.of("urn:sal:restconf:event:subscription");
+
+ private static final String DATASTORE_PARAM_NAME = "datastore";
+
+ private static final String SCOPE_PARAM_NAME = "scope";
+
+ private static final String OUTPUT_TYPE_PARAM_NAME = "notification-output-type";
+
+ private static final String NETCONF_BASE = "urn:ietf:params:xml:ns:netconf:base:1.0";
+
+ private static final String NETCONF_BASE_PAYLOAD_NAME = "data";
+
+ private static final QName NETCONF_BASE_QNAME = QName.create(QNameModule.create(XMLNamespace.of(NETCONF_BASE)),
+ NETCONF_BASE_PAYLOAD_NAME).intern();
+
+ private static final QNameModule SAL_REMOTE_AUGMENT = QNameModule.create(NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT,
+ Revision.of("2014-07-08"));
+
+ private static final AugmentationIdentifier SAL_REMOTE_AUG_IDENTIFIER =
+ new AugmentationIdentifier(ImmutableSet.of(
+ QName.create(SAL_REMOTE_AUGMENT, "scope"), QName.create(SAL_REMOTE_AUGMENT, "datastore"),
+ QName.create(SAL_REMOTE_AUGMENT, "notification-output-type")));
+
+ public static final String DATA_SUBSCR = "data-change-event-subscription";
+ private static final String CREATE_DATA_SUBSCR = "create-" + DATA_SUBSCR;
+
+ public static final String NOTIFICATION_STREAM = "notification-stream";
+ private static final String CREATE_NOTIFICATION_STREAM = "create-" + NOTIFICATION_STREAM;
+
+ private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
+ .appendValue(ChronoField.YEAR, 4).appendLiteral('-')
+ .appendValue(ChronoField.MONTH_OF_YEAR, 2).appendLiteral('-')
+ .appendValue(ChronoField.DAY_OF_MONTH, 2).appendLiteral('T')
+ .appendValue(ChronoField.HOUR_OF_DAY, 2).appendLiteral(':')
+ .appendValue(ChronoField.MINUTE_OF_HOUR, 2).appendLiteral(':')
+ .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+ .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
+ .appendOffset("+HH:MM", "Z").toFormatter();
+
+ private final BrokerFacade broker;
+
+ private final ControllerContext controllerContext;
+
+ @Inject
+ public RestconfImpl(final BrokerFacade broker, final ControllerContext controllerContext) {
+ this.broker = broker;
+ this.controllerContext = controllerContext;
+ }
+
+ /**
+ * Factory method.
+ *
+ * @deprecated Just use {@link #RestconfImpl(BrokerFacade, ControllerContext)} constructor instead.
+ */
+ @Deprecated
+ public static RestconfImpl newInstance(final BrokerFacade broker, final ControllerContext controllerContext) {
+ return new RestconfImpl(broker, controllerContext);
+ }
+
+ @Override
+ @Deprecated
+ public NormalizedNodeContext getModules(final UriInfo uriInfo) {
+ final Module restconfModule = getRestconfModule();
+ final var stack = SchemaInferenceStack.of(controllerContext.getGlobalSchema());
+ final var restconf = QName.create(restconfModule.getQNameModule(),
+ Draft02.RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE);
+ stack.enterGrouping(restconf);
+ stack.enterSchemaTree(restconf);
+ final var modules = QName.create(restconf, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
+ final var modulesSchemaNode = stack.enterSchemaTree(modules);
+ checkState(modulesSchemaNode instanceof ContainerSchemaNode);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> moduleContainerBuilder =
+ SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) modulesSchemaNode);
+ moduleContainerBuilder.withChild(makeModuleMapNode(controllerContext.getAllModules()));
+
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofStack(stack, null),
+ moduleContainerBuilder.build(), QueryParametersParser.parseWriterParameters(uriInfo));
+ }
+
+ /**
+ * Valid only for mount point.
+ */
+ @Override
+ @Deprecated
+ public NormalizedNodeContext getModules(final String identifier, final UriInfo uriInfo) {
+ if (!identifier.contains(ControllerContext.MOUNT)) {
+ final String errMsg = "URI has bad format. If modules behind mount point should be showed,"
+ + " URI has to end with " + ControllerContext.MOUNT;
+ LOG.debug("{} for {}", errMsg, identifier);
+ throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ final InstanceIdentifierContext mountPointIdentifier =
+ controllerContext.toMountPointIdentifier(identifier);
+ final DOMMountPoint mountPoint = mountPointIdentifier.getMountPoint();
+ final MapNode mountPointModulesMap = makeModuleMapNode(controllerContext.getAllModules(mountPoint));
+
+ final Module restconfModule = getRestconfModule();
+ final var stack = SchemaInferenceStack.of(controllerContext.getGlobalSchema());
+ final var restconf = QName.create(restconfModule.getQNameModule(),
+ Draft02.RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE);
+ stack.enterGrouping(restconf);
+ stack.enterSchemaTree(restconf);
+ final var modules = QName.create(restconf, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
+ final var modulesSchemaNode = stack.enterSchemaTree(modules);
+ checkState(modulesSchemaNode instanceof ContainerSchemaNode);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> moduleContainerBuilder =
+ SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) modulesSchemaNode);
+ moduleContainerBuilder.withChild(mountPointModulesMap);
+
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofStack(stack, null),
+ moduleContainerBuilder.build(), QueryParametersParser.parseWriterParameters(uriInfo));
+ }
+
+ @Override
+ @Deprecated
+ public NormalizedNodeContext getModule(final String identifier, final UriInfo uriInfo) {
+ final Entry<String, Revision> nameRev = getModuleNameAndRevision(requireNonNull(identifier));
+ final Module module;
+ final DOMMountPoint mountPoint;
+ if (identifier.contains(ControllerContext.MOUNT)) {
+ final InstanceIdentifierContext mountPointIdentifier =
+ controllerContext.toMountPointIdentifier(identifier);
+ mountPoint = mountPointIdentifier.getMountPoint();
+ module = controllerContext.findModuleByNameAndRevision(mountPoint, nameRev.getKey(),
+ nameRev.getValue());
+ } else {
+ mountPoint = null;
+ module = controllerContext.findModuleByNameAndRevision(nameRev.getKey(), nameRev.getValue());
+ }
+
+ if (module == null) {
+ LOG.debug("Module with name '{}' and revision '{}' was not found.", nameRev.getKey(), nameRev.getValue());
+ throw new RestconfDocumentedException("Module with name '" + nameRev.getKey() + "' and revision '"
+ + nameRev.getValue() + "' was not found.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
+ }
+
+ final Module restconfModule = getRestconfModule();
+ final var stack = SchemaInferenceStack.of(controllerContext.getGlobalSchema());
+ final var restconf = QName.create(restconfModule.getQNameModule(),
+ Draft02.RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE);
+ stack.enterGrouping(restconf);
+ stack.enterSchemaTree(restconf);
+ stack.enterSchemaTree(QName.create(restconf, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE));
+ stack.enterSchemaTree(QName.create(restconf, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE));
+
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofStack(stack, mountPoint),
+ makeModuleMapNode(Set.of(module)), QueryParametersParser.parseWriterParameters(uriInfo));
+ }
+
+ @Override
+ @Deprecated
+ public NormalizedNodeContext getAvailableStreams(final UriInfo uriInfo) {
+ final Set<String> availableStreams = Notificator.getStreamNames();
+ final Module restconfModule = getRestconfModule();
+ final DataSchemaNode streamSchemaNode = controllerContext
+ .getRestconfModuleRestConfSchemaNode(restconfModule, Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE);
+ checkState(streamSchemaNode instanceof ListSchemaNode);
+
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> listStreamsBuilder =
+ SchemaAwareBuilders.mapBuilder((ListSchemaNode) streamSchemaNode);
+
+ for (final String streamName : availableStreams) {
+ listStreamsBuilder.withChild(toStreamEntryNode(streamName, streamSchemaNode));
+ }
+
+ final var stack = SchemaInferenceStack.of(controllerContext.getGlobalSchema());
+ final var restconf = QName.create(restconfModule.getQNameModule(),
+ Draft02.RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE);
+ stack.enterGrouping(restconf);
+ stack.enterSchemaTree(restconf);
+ final var streams = QName.create(restconf, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
+ final var streamsContainerSchemaNode = stack.enterSchemaTree(streams);
+ checkState(streamsContainerSchemaNode instanceof ContainerSchemaNode);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> streamsContainerBuilder =
+ SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) streamsContainerSchemaNode);
+ streamsContainerBuilder.withChild(listStreamsBuilder.build());
+
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofStack(stack),
+ streamsContainerBuilder.build(), QueryParametersParser.parseWriterParameters(uriInfo));
+ }
+
+ @Override
+ @Deprecated
+ public String getOperationsJSON() {
+ return OperationsContent.JSON.bodyFor(controllerContext.getGlobalSchema());
+ }
+
+ @Override
+ @Deprecated
+ public String getOperationsXML() {
+ return OperationsContent.XML.bodyFor(controllerContext.getGlobalSchema());
+ }
+
+ @Override
+ @Deprecated
+ public NormalizedNodeContext getOperations(final String identifier, final UriInfo uriInfo) {
+ if (!identifier.contains(ControllerContext.MOUNT)) {
+ final String errMsg = "URI has bad format. If operations behind mount point should be showed, URI has to "
+ + " end with " + ControllerContext.MOUNT;
+ LOG.debug("{} for {}", errMsg, identifier);
+ throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ final InstanceIdentifierContext mountPointIdentifier = controllerContext.toMountPointIdentifier(identifier);
+ final DOMMountPoint mountPoint = mountPointIdentifier.getMountPoint();
+ final var entry = OperationsResourceUtils.contextForModelContext(modelContext(mountPoint), mountPoint);
+ return new NormalizedNodeContext(entry.getKey(), entry.getValue());
+ }
+
+ private Module getRestconfModule() {
+ final Module restconfModule = controllerContext.getRestconfModule();
+ if (restconfModule == null) {
+ LOG.debug("ietf-restconf module was not found.");
+ throw new RestconfDocumentedException("ietf-restconf module was not found.", ErrorType.APPLICATION,
+ ErrorTag.OPERATION_NOT_SUPPORTED);
+ }
+
+ return restconfModule;
+ }
+
+ private static Entry<String, Revision> getModuleNameAndRevision(final String identifier) {
+ final int mountIndex = identifier.indexOf(ControllerContext.MOUNT);
+ String moduleNameAndRevision = "";
+ if (mountIndex >= 0) {
+ moduleNameAndRevision = identifier.substring(mountIndex + ControllerContext.MOUNT.length());
+ } else {
+ moduleNameAndRevision = identifier;
+ }
+
+ final Splitter splitter = Splitter.on('/').omitEmptyStrings();
+ final List<String> pathArgs = splitter.splitToList(moduleNameAndRevision);
+ if (pathArgs.size() < 2) {
+ LOG.debug("URI has bad format. It should be \'moduleName/yyyy-MM-dd\' {}", identifier);
+ throw new RestconfDocumentedException(
+ "URI has bad format. End of URI should be in format \'moduleName/yyyy-MM-dd\'", ErrorType.PROTOCOL,
+ ErrorTag.INVALID_VALUE);
+ }
+
+ try {
+ return Map.entry(pathArgs.get(0), Revision.of(pathArgs.get(1)));
+ } catch (final DateTimeParseException e) {
+ LOG.debug("URI has bad format. It should be \'moduleName/yyyy-MM-dd\' {}", identifier);
+ throw new RestconfDocumentedException("URI has bad format. It should be \'moduleName/yyyy-MM-dd\'",
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, e);
+ }
+ }
+
+ @Override
+ public Object getRoot() {
+ return null;
+ }
+
+ @Override
+ public NormalizedNodeContext invokeRpc(final String identifier, final NormalizedNodeContext payload,
+ final UriInfo uriInfo) {
+ if (payload == null) {
+ // no payload specified, reroute this to no payload invokeRpc implementation
+ return invokeRpc(identifier, uriInfo);
+ }
+
+ final SchemaNode schema = payload.getInstanceIdentifierContext().getSchemaNode();
+ final ListenableFuture<? extends DOMRpcResult> response;
+ final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
+ final NormalizedNode input = nonnullInput(schema, payload.getData());
+ final EffectiveModelContext schemaContext;
+
+ if (mountPoint != null) {
+ final Optional<DOMRpcService> mountRpcServices = mountPoint.getService(DOMRpcService.class);
+ if (mountRpcServices.isEmpty()) {
+ LOG.debug("Error: Rpc service is missing.");
+ throw new RestconfDocumentedException("Rpc service is missing.");
+ }
+ schemaContext = modelContext(mountPoint);
+ response = mountRpcServices.get().invokeRpc(schema.getQName(), input);
+ } else {
+ final XMLNamespace namespace = schema.getQName().getNamespace();
+ if (namespace.toString().equals(SAL_REMOTE_NAMESPACE)) {
+ if (identifier.contains(CREATE_DATA_SUBSCR)) {
+ response = invokeSalRemoteRpcSubscribeRPC(payload);
+ } else if (identifier.contains(CREATE_NOTIFICATION_STREAM)) {
+ response = invokeSalRemoteRpcNotifiStrRPC(payload);
+ } else {
+ final String msg = "Not supported operation";
+ LOG.warn(msg);
+ throw new RestconfDocumentedException(msg, ErrorType.RPC, ErrorTag.OPERATION_NOT_SUPPORTED);
+ }
+ } else {
+ response = broker.invokeRpc(schema.getQName(), input);
+ }
+ schemaContext = controllerContext.getGlobalSchema();
+ }
+
+ final DOMRpcResult result = checkRpcResponse(response);
+
+ final NormalizedNode resultData;
+ if (result != null && result.getResult() != null) {
+ resultData = result.getResult();
+ } else {
+ resultData = null;
+ }
+
+ if (resultData != null && ((ContainerNode) resultData).isEmpty()) {
+ throw new WebApplicationException(Response.Status.NO_CONTENT);
+ }
+
+ final var resultNodeSchema = (RpcDefinition) payload.getInstanceIdentifierContext().getSchemaNode();
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofRpcOutput(schemaContext, resultNodeSchema, mountPoint), resultData,
+ QueryParametersParser.parseWriterParameters(uriInfo));
+ }
+
+ @SuppressFBWarnings(value = "NP_LOAD_OF_KNOWN_NULL_VALUE",
+ justification = "Looks like a false positive, see below FIXME")
+ private NormalizedNodeContext invokeRpc(final String identifier, final UriInfo uriInfo) {
+ final DOMMountPoint mountPoint;
+ final String identifierEncoded;
+ final EffectiveModelContext schemaContext;
+ if (identifier.contains(ControllerContext.MOUNT)) {
+ // mounted RPC call - look up mount instance.
+ final InstanceIdentifierContext mountPointId = controllerContext.toMountPointIdentifier(identifier);
+ mountPoint = mountPointId.getMountPoint();
+ schemaContext = modelContext(mountPoint);
+ final int startOfRemoteRpcName =
+ identifier.lastIndexOf(ControllerContext.MOUNT) + ControllerContext.MOUNT.length() + 1;
+ final String remoteRpcName = identifier.substring(startOfRemoteRpcName);
+ identifierEncoded = remoteRpcName;
+
+ } else if (identifier.indexOf('/') == CHAR_NOT_FOUND) {
+ identifierEncoded = identifier;
+ mountPoint = null;
+ schemaContext = controllerContext.getGlobalSchema();
+ } else {
+ LOG.debug("Identifier {} cannot contain slash character (/).", identifier);
+ throw new RestconfDocumentedException(String.format("Identifier %n%s%ncan\'t contain slash character (/).%n"
+ + "If slash is part of identifier name then use %%2F placeholder.", identifier), ErrorType.PROTOCOL,
+ ErrorTag.INVALID_VALUE);
+ }
+
+ final String identifierDecoded = ControllerContext.urlPathArgDecode(identifierEncoded);
+ final RpcDefinition rpc;
+ if (mountPoint == null) {
+ rpc = controllerContext.getRpcDefinition(identifierDecoded);
+ } else {
+ rpc = findRpc(modelContext(mountPoint), identifierDecoded);
+ }
+
+ if (rpc == null) {
+ LOG.debug("RPC {} does not exist.", identifierDecoded);
+ throw new RestconfDocumentedException("RPC does not exist.", ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT);
+ }
+
+ if (!rpc.getInput().getChildNodes().isEmpty()) {
+ LOG.debug("No input specified for RPC {} with an input section", rpc);
+ throw new RestconfDocumentedException("No input specified for RPC " + rpc
+ + " with an input section defined", ErrorType.RPC, ErrorTag.MISSING_ELEMENT);
+ }
+
+ final ContainerNode input = defaultInput(rpc.getQName());
+ final ListenableFuture<? extends DOMRpcResult> response;
+ if (mountPoint != null) {
+ final Optional<DOMRpcService> mountRpcServices = mountPoint.getService(DOMRpcService.class);
+ if (mountRpcServices.isEmpty()) {
+ throw new RestconfDocumentedException("Rpc service is missing.");
+ }
+ response = mountRpcServices.get().invokeRpc(rpc.getQName(), input);
+ } else {
+ response = broker.invokeRpc(rpc.getQName(), input);
+ }
+
+ final NormalizedNode result = checkRpcResponse(response).getResult();
+ if (result != null && ((ContainerNode) result).isEmpty()) {
+ throw new WebApplicationException(Response.Status.NO_CONTENT);
+ }
+
+ // FIXME: in reference to the above @SupressFBWarnings: "mountPoint" reference here trips up SpotBugs, as it
+ // thinks it can only ever be null. Except it can very much be non-null. The core problem is the horrible
+ // structure of this code where we have a sh*tload of checks for mountpoint above and all over the
+ // codebase where all that difference should have been properly encapsulated.
+ //
+ // This is legacy code, so if anybody cares to do that refactor, feel free to contribute, but I am not
+ // doing that work.
+ final var iic = mountPoint == null ? InstanceIdentifierContext.ofLocalRpcOutput(schemaContext, rpc)
+ : InstanceIdentifierContext.ofMountPointRpcOutput(mountPoint, schemaContext, rpc);
+ return new NormalizedNodeContext(iic, result, QueryParametersParser.parseWriterParameters(uriInfo));
+ }
+
+ private static @NonNull NormalizedNode nonnullInput(final SchemaNode rpc, final NormalizedNode input) {
+ return input != null ? input : defaultInput(rpc.getQName());
+ }
+
+ private static @NonNull ContainerNode defaultInput(final QName rpcName) {
+ return ImmutableNodes.containerNode(YangConstants.operationInputQName(rpcName.getModule()));
+ }
+
+ @SuppressWarnings("checkstyle:avoidHidingCauseException")
+ private static DOMRpcResult checkRpcResponse(final ListenableFuture<? extends DOMRpcResult> response) {
+ if (response == null) {
+ return null;
+ }
+ try {
+ final DOMRpcResult retValue = response.get();
+ if (retValue.getErrors().isEmpty()) {
+ return retValue;
+ }
+ LOG.debug("RpcError message {}", retValue.getErrors());
+ throw new RestconfDocumentedException("RpcError message", null, retValue.getErrors());
+ } catch (final InterruptedException e) {
+ final String errMsg = "The operation was interrupted while executing and did not complete.";
+ LOG.debug("Rpc Interrupt - {}", errMsg, e);
+ throw new RestconfDocumentedException(errMsg, ErrorType.RPC, ErrorTag.PARTIAL_OPERATION, e);
+ } catch (final ExecutionException e) {
+ LOG.debug("Execution RpcError: ", e);
+ Throwable cause = e.getCause();
+ if (cause == null) {
+ throw new RestconfDocumentedException("The operation encountered an unexpected error while executing.",
+ e);
+ }
+ while (cause.getCause() != null) {
+ cause = cause.getCause();
+ }
+
+ if (cause instanceof IllegalArgumentException) {
+ throw new RestconfDocumentedException(cause.getMessage(), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ } else if (cause instanceof DOMRpcImplementationNotAvailableException) {
+ throw new RestconfDocumentedException(cause.getMessage(), ErrorType.APPLICATION,
+ ErrorTag.OPERATION_NOT_SUPPORTED);
+ }
+ throw new RestconfDocumentedException("The operation encountered an unexpected error while executing.",
+ cause);
+ } catch (final CancellationException e) {
+ final String errMsg = "The operation was cancelled while executing.";
+ LOG.debug("Cancel RpcExecution: {}", errMsg, e);
+ throw new RestconfDocumentedException(errMsg, ErrorType.RPC, ErrorTag.PARTIAL_OPERATION);
+ }
+ }
+
+ private static void validateInput(final SchemaNode inputSchema, final NormalizedNodeContext payload) {
+ if (inputSchema != null && payload.getData() == null) {
+ // expected a non null payload
+ throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ } else if (inputSchema == null && payload.getData() != null) {
+ // did not expect any input
+ throw new RestconfDocumentedException("No input expected.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ }
+ }
+
+ private ListenableFuture<DOMRpcResult> invokeSalRemoteRpcSubscribeRPC(final NormalizedNodeContext payload) {
+ final ContainerNode value = (ContainerNode) payload.getData();
+ final QName rpcQName = payload.getInstanceIdentifierContext().getSchemaNode().getQName();
+ final Optional<DataContainerChild> path =
+ value.findChildByArg(new NodeIdentifier(QName.create(rpcQName, "path")));
+ final Object pathValue = path.isPresent() ? path.get().body() : null;
+
+ if (!(pathValue instanceof YangInstanceIdentifier)) {
+ LOG.debug("Instance identifier {} was not normalized correctly", rpcQName);
+ throw new RestconfDocumentedException("Instance identifier was not normalized correctly",
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
+ }
+
+ final YangInstanceIdentifier pathIdentifier = (YangInstanceIdentifier) pathValue;
+ final String streamName;
+ NotificationOutputType outputType = null;
+ if (!pathIdentifier.isEmpty()) {
+ final String fullRestconfIdentifier =
+ DATA_SUBSCR + controllerContext.toFullRestconfIdentifier(pathIdentifier, null);
+
+ LogicalDatastoreType datastore =
+ parseEnumTypeParameter(value, LogicalDatastoreType.class, DATASTORE_PARAM_NAME);
+ datastore = datastore == null ? DEFAULT_DATASTORE : datastore;
+
+ Scope scope = parseEnumTypeParameter(value, Scope.class, SCOPE_PARAM_NAME);
+ scope = scope == null ? Scope.BASE : scope;
+
+ outputType = parseEnumTypeParameter(value, NotificationOutputType.class, OUTPUT_TYPE_PARAM_NAME);
+ outputType = outputType == null ? NotificationOutputType.XML : outputType;
+
+ streamName = Notificator
+ .createStreamNameFromUri(fullRestconfIdentifier + "/datastore=" + datastore + "/scope=" + scope);
+ } else {
+ streamName = CREATE_DATA_SUBSCR;
+ }
+
+ if (Strings.isNullOrEmpty(streamName)) {
+ LOG.debug("Path is empty or contains value node which is not Container or List built-in type at {}",
+ pathIdentifier);
+ throw new RestconfDocumentedException("Path is empty or contains value node which is not Container or List "
+ + "built-in type.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ if (!Notificator.existListenerFor(streamName)) {
+ Notificator.createListener(pathIdentifier, streamName, outputType, controllerContext);
+ }
+
+ return Futures.immediateFuture(new DefaultDOMRpcResult(Builders.containerBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create(rpcQName, "output")))
+ .withChild(ImmutableNodes.leafNode(QName.create(rpcQName, "stream-name"), streamName))
+ .build()));
+ }
+
+ private static RpcDefinition findRpc(final SchemaContext schemaContext, final String identifierDecoded) {
+ final String[] splittedIdentifier = identifierDecoded.split(":");
+ if (splittedIdentifier.length != 2) {
+ LOG.debug("{} could not be split to 2 parts (module:rpc name)", identifierDecoded);
+ throw new RestconfDocumentedException(identifierDecoded + " could not be split to 2 parts "
+ + "(module:rpc name)", ErrorType.APPLICATION, ErrorTag.INVALID_VALUE);
+ }
+ for (final Module module : schemaContext.getModules()) {
+ if (module.getName().equals(splittedIdentifier[0])) {
+ for (final RpcDefinition rpcDefinition : module.getRpcs()) {
+ if (rpcDefinition.getQName().getLocalName().equals(splittedIdentifier[1])) {
+ return rpcDefinition;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public NormalizedNodeContext readConfigurationData(final String identifier, final UriInfo uriInfo) {
+ boolean withDefaUsed = false;
+ String withDefa = null;
+
+ for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+ switch (entry.getKey()) {
+ case "with-defaults":
+ if (!withDefaUsed) {
+ withDefaUsed = true;
+ withDefa = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("With-defaults parameter can be used only once.");
+ }
+ break;
+ default:
+ LOG.info("Unknown key : {}.", entry.getKey());
+ break;
+ }
+ }
+
+ // TODO: this flag is always ignored
+ boolean tagged = false;
+ if (withDefaUsed) {
+ if ("report-all-tagged".equals(withDefa)) {
+ tagged = true;
+ withDefa = null;
+ }
+ if ("report-all".equals(withDefa)) {
+ withDefa = null;
+ }
+ }
+
+ final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
+ final DOMMountPoint mountPoint = iiWithData.getMountPoint();
+ NormalizedNode data = null;
+ final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
+ if (mountPoint != null) {
+ data = broker.readConfigurationData(mountPoint, normalizedII, withDefa);
+ } else {
+ data = broker.readConfigurationData(normalizedII, withDefa);
+ }
+ if (data == null) {
+ throw dataMissing(identifier);
+ }
+ return new NormalizedNodeContext(iiWithData, data, QueryParametersParser.parseWriterParameters(uriInfo));
+ }
+
+ @Override
+ public NormalizedNodeContext readOperationalData(final String identifier, final UriInfo uriInfo) {
+ final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
+ final DOMMountPoint mountPoint = iiWithData.getMountPoint();
+ NormalizedNode data = null;
+ final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
+ if (mountPoint != null) {
+ data = broker.readOperationalData(mountPoint, normalizedII);
+ } else {
+ data = broker.readOperationalData(normalizedII);
+ }
+ if (data == null) {
+ throw dataMissing(identifier);
+ }
+ return new NormalizedNodeContext(iiWithData, data, QueryParametersParser.parseWriterParameters(uriInfo));
+ }
+
+ private static RestconfDocumentedException dataMissing(final String identifier) {
+ LOG.debug("Request could not be completed because the relevant data model content does not exist {}",
+ identifier);
+ return new RestconfDocumentedException("Request could not be completed because the relevant data model content "
+ + "does not exist", ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
+ }
+
+ @Override
+ public Response updateConfigurationData(final String identifier, final NormalizedNodeContext payload,
+ final UriInfo uriInfo) {
+ boolean insertUsed = false;
+ boolean pointUsed = false;
+ String insert = null;
+ String point = null;
+
+ for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+ switch (entry.getKey()) {
+ case "insert":
+ if (!insertUsed) {
+ insertUsed = true;
+ insert = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("Insert parameter can be used only once.");
+ }
+ break;
+ case "point":
+ if (!pointUsed) {
+ pointUsed = true;
+ point = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("Point parameter can be used only once.");
+ }
+ break;
+ default:
+ throw new RestconfDocumentedException("Bad parameter for post: " + entry.getKey());
+ }
+ }
+
+ if (pointUsed && !insertUsed) {
+ throw new RestconfDocumentedException("Point parameter can't be used without Insert parameter.");
+ }
+ if (pointUsed && (insert.equals("first") || insert.equals("last"))) {
+ throw new RestconfDocumentedException(
+ "Point parameter can be used only with 'after' or 'before' values of Insert parameter.");
+ }
+
+ requireNonNull(identifier);
+
+ final InstanceIdentifierContext iiWithData = payload.getInstanceIdentifierContext();
+
+ validateInput(iiWithData.getSchemaNode(), payload);
+ validateTopLevelNodeName(payload, iiWithData.getInstanceIdentifier());
+ validateListKeysEqualityInPayloadAndUri(payload);
+
+ final DOMMountPoint mountPoint = iiWithData.getMountPoint();
+ final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
+
+ /*
+ * There is a small window where another write transaction could be
+ * updating the same data simultaneously and we get an
+ * OptimisticLockFailedException. This error is likely transient and The
+ * WriteTransaction#submit API docs state that a retry will likely
+ * succeed. So we'll try again if that scenario occurs. If it fails a
+ * third time then it probably will never succeed so we'll fail in that
+ * case.
+ *
+ * By retrying we're attempting to hide the internal implementation of
+ * the data store and how it handles concurrent updates from the
+ * restconf client. The client has instructed us to put the data and we
+ * should make every effort to do so without pushing optimistic lock
+ * failures back to the client and forcing them to handle it via retry
+ * (and having to document the behavior).
+ */
+ PutResult result = null;
+ int tries = 2;
+ while (true) {
+ if (mountPoint != null) {
+
+ result = broker.commitMountPointDataPut(mountPoint, normalizedII, payload.getData(), insert,
+ point);
+ } else {
+ result = broker.commitConfigurationDataPut(controllerContext.getGlobalSchema(), normalizedII,
+ payload.getData(), insert, point);
+ }
+
+ try {
+ result.getFutureOfPutData().get();
+ } catch (final InterruptedException e) {
+ LOG.debug("Update failed for {}", identifier, e);
+ throw new RestconfDocumentedException(e.getMessage(), e);
+ } catch (final ExecutionException e) {
+ final TransactionCommitFailedException failure = Throwables.getCauseAs(e,
+ TransactionCommitFailedException.class);
+ if (failure instanceof OptimisticLockFailedException) {
+ if (--tries <= 0) {
+ LOG.debug("Got OptimisticLockFailedException on last try - failing {}", identifier);
+ throw new RestconfDocumentedException(e.getMessage(), e, failure.getErrorList());
+ }
+
+ LOG.debug("Got OptimisticLockFailedException - trying again {}", identifier);
+ continue;
+ }
+
+ LOG.debug("Update failed for {}", identifier, e);
+ throw RestconfDocumentedException.decodeAndThrow(e.getMessage(), failure);
+ }
+
+ return Response.status(result.getStatus()).build();
+ }
+ }
+
+ private static void validateTopLevelNodeName(final NormalizedNodeContext node,
+ final YangInstanceIdentifier identifier) {
+
+ final String payloadName = node.getData().getIdentifier().getNodeType().getLocalName();
+
+ // no arguments
+ if (identifier.isEmpty()) {
+ // no "data" payload
+ if (!node.getData().getIdentifier().getNodeType().equals(NETCONF_BASE_QNAME)) {
+ throw new RestconfDocumentedException("Instance identifier has to contain at least one path argument",
+ ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ }
+ // any arguments
+ } else {
+ final String identifierName = identifier.getLastPathArgument().getNodeType().getLocalName();
+ if (!payloadName.equals(identifierName)) {
+ throw new RestconfDocumentedException(
+ "Payload name (" + payloadName + ") is different from identifier name (" + identifierName + ")",
+ ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ }
+ }
+ }
+
+ /**
+ * Validates whether keys in {@code payload} are equal to values of keys in
+ * {@code iiWithData} for list schema node.
+ *
+ * @throws RestconfDocumentedException
+ * if key values or key count in payload and URI isn't equal
+ *
+ */
+ private static void validateListKeysEqualityInPayloadAndUri(final NormalizedNodeContext payload) {
+ checkArgument(payload != null);
+ final InstanceIdentifierContext iiWithData = payload.getInstanceIdentifierContext();
+ final PathArgument lastPathArgument = iiWithData.getInstanceIdentifier().getLastPathArgument();
+ final SchemaNode schemaNode = iiWithData.getSchemaNode();
+ final NormalizedNode data = payload.getData();
+ if (schemaNode instanceof ListSchemaNode) {
+ final List<QName> keyDefinitions = ((ListSchemaNode) schemaNode).getKeyDefinition();
+ if (lastPathArgument instanceof NodeIdentifierWithPredicates && data instanceof MapEntryNode) {
+ final Map<QName, Object> uriKeyValues = ((NodeIdentifierWithPredicates) lastPathArgument).asMap();
+ isEqualUriAndPayloadKeyValues(uriKeyValues, (MapEntryNode) data, keyDefinitions);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ public static void isEqualUriAndPayloadKeyValues(final Map<QName, Object> uriKeyValues, final MapEntryNode payload,
+ final List<QName> keyDefinitions) {
+
+ final Map<QName, Object> mutableCopyUriKeyValues = new HashMap<>(uriKeyValues);
+ for (final QName keyDefinition : keyDefinitions) {
+ final Object uriKeyValue = RestconfDocumentedException.throwIfNull(
+ // should be caught during parsing URI to InstanceIdentifier
+ mutableCopyUriKeyValues.remove(keyDefinition), ErrorType.PROTOCOL, ErrorTag.DATA_MISSING,
+ "Missing key %s in URI.", keyDefinition);
+
+ final Object dataKeyValue = payload.getIdentifier().getValue(keyDefinition);
+
+ if (!Objects.deepEquals(uriKeyValue, dataKeyValue)) {
+ final String errMsg = "The value '" + uriKeyValue + "' for key '" + keyDefinition.getLocalName()
+ + "' specified in the URI doesn't match the value '" + dataKeyValue
+ + "' specified in the message body. ";
+ throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+ }
+ }
+
+ @Override
+ public Response createConfigurationData(final String identifier, final NormalizedNodeContext payload,
+ final UriInfo uriInfo) {
+ return createConfigurationData(payload, uriInfo);
+ }
+
+ @Override
+ public Response createConfigurationData(final NormalizedNodeContext payload, final UriInfo uriInfo) {
+ if (payload == null) {
+ throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ }
+ final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
+ final InstanceIdentifierContext iiWithData = payload.getInstanceIdentifierContext();
+ final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
+
+ boolean insertUsed = false;
+ boolean pointUsed = false;
+ String insert = null;
+ String point = null;
+
+ if (uriInfo != null) {
+ for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+ switch (entry.getKey()) {
+ case "insert":
+ if (!insertUsed) {
+ insertUsed = true;
+ insert = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("Insert parameter can be used only once.");
+ }
+ break;
+ case "point":
+ if (!pointUsed) {
+ pointUsed = true;
+ point = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("Point parameter can be used only once.");
+ }
+ break;
+ default:
+ throw new RestconfDocumentedException("Bad parameter for post: " + entry.getKey());
+ }
+ }
+ }
+
+ if (pointUsed && !insertUsed) {
+ throw new RestconfDocumentedException("Point parameter can't be used without Insert parameter.");
+ }
+ if (pointUsed && (insert.equals("first") || insert.equals("last"))) {
+ throw new RestconfDocumentedException(
+ "Point parameter can be used only with 'after' or 'before' values of Insert parameter.");
+ }
+
+ FluentFuture<? extends CommitInfo> future;
+ if (mountPoint != null) {
+ future = broker.commitConfigurationDataPost(mountPoint, normalizedII, payload.getData(), insert,
+ point);
+ } else {
+ future = broker.commitConfigurationDataPost(controllerContext.getGlobalSchema(), normalizedII,
+ payload.getData(), insert, point);
+ }
+
+ try {
+ future.get();
+ } catch (final InterruptedException e) {
+ LOG.info("Error creating data {}", uriInfo != null ? uriInfo.getPath() : "", e);
+ throw new RestconfDocumentedException(e.getMessage(), e);
+ } catch (final ExecutionException e) {
+ LOG.info("Error creating data {}", uriInfo != null ? uriInfo.getPath() : "", e);
+ throw RestconfDocumentedException.decodeAndThrow(e.getMessage(), Throwables.getCauseAs(e,
+ TransactionCommitFailedException.class));
+ }
+
+ LOG.trace("Successfuly created data.");
+
+ final ResponseBuilder responseBuilder = Response.status(Status.NO_CONTENT);
+ // FIXME: Provide path to result.
+ final URI location = resolveLocation(uriInfo, "", mountPoint, normalizedII);
+ if (location != null) {
+ responseBuilder.location(location);
+ }
+ return responseBuilder.build();
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ private URI resolveLocation(final UriInfo uriInfo, final String uriBehindBase, final DOMMountPoint mountPoint,
+ final YangInstanceIdentifier normalizedII) {
+ if (uriInfo == null) {
+ // This is null if invoked internally
+ return null;
+ }
+
+ final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
+ uriBuilder.path("config");
+ try {
+ uriBuilder.path(controllerContext.toFullRestconfIdentifier(normalizedII, mountPoint));
+ } catch (final Exception e) {
+ LOG.info("Location for instance identifier {} was not created", normalizedII, e);
+ return null;
+ }
+ return uriBuilder.build();
+ }
+
+ @Override
+ public Response deleteConfigurationData(final String identifier) {
+ final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
+ final DOMMountPoint mountPoint = iiWithData.getMountPoint();
+ final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
+
+ final FluentFuture<? extends CommitInfo> future;
+ if (mountPoint != null) {
+ future = broker.commitConfigurationDataDelete(mountPoint, normalizedII);
+ } else {
+ future = broker.commitConfigurationDataDelete(normalizedII);
+ }
+
+ try {
+ future.get();
+ } catch (final InterruptedException e) {
+ throw new RestconfDocumentedException(e.getMessage(), e);
+ } catch (final ExecutionException e) {
+ final Optional<Throwable> searchedException = Iterables.tryFind(Throwables.getCausalChain(e),
+ Predicates.instanceOf(ModifiedNodeDoesNotExistException.class)).toJavaUtil();
+ if (searchedException.isPresent()) {
+ throw new RestconfDocumentedException("Data specified for delete doesn't exist.", ErrorType.APPLICATION,
+ ErrorTag.DATA_MISSING, e);
+ }
+
+ throw RestconfDocumentedException.decodeAndThrow(e.getMessage(), Throwables.getCauseAs(e,
+ TransactionCommitFailedException.class));
+ }
+
+ return Response.status(Status.OK).build();
+ }
+
+ /**
+ * Subscribes to some path in schema context (stream) to listen on changes
+ * on this stream.
+ *
+ * <p>
+ * Additional parameters for subscribing to stream are loaded via rpc input
+ * parameters:
+ * <ul>
+ * <li>datastore - default CONFIGURATION (other values of
+ * {@link LogicalDatastoreType} enum type)</li>
+ * <li>scope - default BASE (other values of {@link Scope})</li>
+ * </ul>
+ */
+ @Override
+ public NormalizedNodeContext subscribeToStream(final String identifier, final UriInfo uriInfo) {
+ boolean startTimeUsed = false;
+ boolean stopTimeUsed = false;
+ Instant start = Instant.now();
+ Instant stop = null;
+ boolean filterUsed = false;
+ String filter = null;
+ boolean leafNodesOnlyUsed = false;
+ boolean leafNodesOnly = false;
+ boolean skipNotificationDataUsed = false;
+ boolean skipNotificationData = false;
+
+ for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+ switch (entry.getKey()) {
+ case "start-time":
+ if (!startTimeUsed) {
+ startTimeUsed = true;
+ start = parseDateFromQueryParam(entry);
+ } else {
+ throw new RestconfDocumentedException("Start-time parameter can be used only once.");
+ }
+ break;
+ case "stop-time":
+ if (!stopTimeUsed) {
+ stopTimeUsed = true;
+ stop = parseDateFromQueryParam(entry);
+ } else {
+ throw new RestconfDocumentedException("Stop-time parameter can be used only once.");
+ }
+ break;
+ case "filter":
+ if (!filterUsed) {
+ filterUsed = true;
+ filter = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("Filter parameter can be used only once.");
+ }
+ break;
+ case "odl-leaf-nodes-only":
+ if (!leafNodesOnlyUsed) {
+ leafNodesOnlyUsed = true;
+ leafNodesOnly = Boolean.parseBoolean(entry.getValue().iterator().next());
+ } else {
+ throw new RestconfDocumentedException("Odl-leaf-nodes-only parameter can be used only once.");
+ }
+ break;
+ case "odl-skip-notification-data":
+ if (!skipNotificationDataUsed) {
+ skipNotificationDataUsed = true;
+ skipNotificationData = Boolean.parseBoolean(entry.getValue().iterator().next());
+ } else {
+ throw new RestconfDocumentedException(
+ "Odl-skip-notification-data parameter can be used only once.");
+ }
+ break;
+ default:
+ throw new RestconfDocumentedException("Bad parameter used with notifications: " + entry.getKey());
+ }
+ }
+ if (!startTimeUsed && stopTimeUsed) {
+ throw new RestconfDocumentedException("Stop-time parameter has to be used with start-time parameter.");
+ }
+ URI response = null;
+ if (identifier.contains(DATA_SUBSCR)) {
+ response = dataSubs(identifier, uriInfo, start, stop, filter, leafNodesOnly, skipNotificationData);
+ } else if (identifier.contains(NOTIFICATION_STREAM)) {
+ response = notifStream(identifier, uriInfo, start, stop, filter);
+ }
+
+ if (response != null) {
+ // prepare node with value of location
+
+ final QName qnameBase = QName.create("subscribe:to:notification", "2016-10-28", "notifi");
+ final QName locationQName = QName.create(qnameBase, "location");
+
+ final var stack = SchemaInferenceStack.of(controllerContext.getGlobalSchema());
+ stack.enterSchemaTree(qnameBase);
+ stack.enterSchemaTree(locationQName);
+
+ // prepare new header with location
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofStack(stack),
+ ImmutableNodes.leafNode(locationQName, response.toString()), ImmutableMap.of("Location", response));
+ }
+
+ final String msg = "Bad type of notification of sal-remote";
+ LOG.warn(msg);
+ throw new RestconfDocumentedException(msg);
+ }
+
+ private static Instant parseDateFromQueryParam(final Entry<String, List<String>> entry) {
+ final DateAndTime event = new DateAndTime(entry.getValue().iterator().next());
+ final String value = event.getValue();
+ final TemporalAccessor p;
+ try {
+ p = FORMATTER.parse(value);
+ } catch (final DateTimeParseException e) {
+ throw new RestconfDocumentedException("Cannot parse of value in date: " + value, e);
+ }
+ return Instant.from(p);
+ }
+
+ /**
+ * Register notification listener by stream name.
+ *
+ * @param identifier
+ * stream name
+ * @param uriInfo
+ * uriInfo
+ * @param stop
+ * stop-time of getting notification
+ * @param start
+ * start-time of getting notification
+ * @param filter
+ * indicate which subset of all possible events are of interest
+ * @return {@link URI} of location
+ */
+ private URI notifStream(final String identifier, final UriInfo uriInfo, final Instant start,
+ final Instant stop, final String filter) {
+ final String streamName = Notificator.createStreamNameFromUri(identifier);
+ if (Strings.isNullOrEmpty(streamName)) {
+ throw new RestconfDocumentedException("Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+ final List<NotificationListenerAdapter> listeners = Notificator.getNotificationListenerFor(streamName);
+ if (listeners == null || listeners.isEmpty()) {
+ throw new RestconfDocumentedException("Stream was not found.", ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_ELEMENT);
+ }
+
+ for (final NotificationListenerAdapter listener : listeners) {
+ broker.registerToListenNotification(listener);
+ listener.setQueryParams(start, Optional.ofNullable(stop), Optional.ofNullable(filter), false, false);
+ }
+
+ final UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder();
+
+ final WebSocketServer webSocketServerInstance = WebSocketServer.getInstance(NOTIFICATION_PORT);
+ final int notificationPort = webSocketServerInstance.getPort();
+
+
+ final UriBuilder uriToWebsocketServerBuilder = uriBuilder.port(notificationPort).scheme(getWsScheme(uriInfo));
+
+ return uriToWebsocketServerBuilder.replacePath(streamName).build();
+ }
+
+ private static String getWsScheme(final UriInfo uriInfo) {
+ URI uri = uriInfo.getAbsolutePath();
+ if (uri == null) {
+ return "ws";
+ }
+ String subscriptionScheme = uri.getScheme().toLowerCase(Locale.ROOT);
+ return subscriptionScheme.equals("https") ? "wss" : "ws";
+ }
+
+ /**
+ * Register data change listener by stream name.
+ *
+ * @param identifier
+ * stream name
+ * @param uriInfo
+ * uri info
+ * @param stop
+ * start-time of getting notification
+ * @param start
+ * stop-time of getting notification
+ * @param filter
+ * indicate which subset of all possible events are of interest
+ * @return {@link URI} of location
+ */
+ private URI dataSubs(final String identifier, final UriInfo uriInfo, final Instant start, final Instant stop,
+ final String filter, final boolean leafNodesOnly, final boolean skipNotificationData) {
+ final String streamName = Notificator.createStreamNameFromUri(identifier);
+ if (Strings.isNullOrEmpty(streamName)) {
+ throw new RestconfDocumentedException("Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ final ListenerAdapter listener = Notificator.getListenerFor(streamName);
+ if (listener == null) {
+ throw new RestconfDocumentedException("Stream was not found.", ErrorType.PROTOCOL,
+ ErrorTag.UNKNOWN_ELEMENT);
+ }
+ listener.setQueryParams(start, Optional.ofNullable(stop), Optional.ofNullable(filter), leafNodesOnly,
+ skipNotificationData);
+
+ final Map<String, String> paramToValues = resolveValuesFromUri(identifier);
+ final LogicalDatastoreType datastore =
+ parserURIEnumParameter(LogicalDatastoreType.class, paramToValues.get(DATASTORE_PARAM_NAME));
+ if (datastore == null) {
+ throw new RestconfDocumentedException("Stream name doesn't contains datastore value (pattern /datastore=)",
+ ErrorType.APPLICATION, ErrorTag.MISSING_ATTRIBUTE);
+ }
+ final Scope scope = parserURIEnumParameter(Scope.class, paramToValues.get(SCOPE_PARAM_NAME));
+ if (scope == null) {
+ throw new RestconfDocumentedException("Stream name doesn't contains datastore value (pattern /scope=)",
+ ErrorType.APPLICATION, ErrorTag.MISSING_ATTRIBUTE);
+ }
+
+ broker.registerToListenDataChanges(datastore, scope, listener);
+
+ final UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder();
+
+ final WebSocketServer webSocketServerInstance = WebSocketServer.getInstance(NOTIFICATION_PORT);
+ final int notificationPort = webSocketServerInstance.getPort();
+
+ final UriBuilder uriToWebsocketServerBuilder = uriBuilder.port(notificationPort).scheme(getWsScheme(uriInfo));
+
+ return uriToWebsocketServerBuilder.replacePath(streamName).build();
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public PatchStatusContext patchConfigurationData(final String identifier, final PatchContext context,
+ final UriInfo uriInfo) {
+ if (context == null) {
+ throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ }
+
+ try {
+ return broker.patchConfigurationDataWithinTransaction(context);
+ } catch (final Exception e) {
+ LOG.debug("Patch transaction failed", e);
+ throw new RestconfDocumentedException(e.getMessage(), e);
+ }
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public PatchStatusContext patchConfigurationData(final PatchContext context, @Context final UriInfo uriInfo) {
+ if (context == null) {
+ throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ }
+
+ try {
+ return broker.patchConfigurationDataWithinTransaction(context);
+ } catch (final Exception e) {
+ LOG.debug("Patch transaction failed", e);
+ throw new RestconfDocumentedException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Load parameter for subscribing to stream from input composite node.
+ *
+ * @param value
+ * contains value
+ * @return enum object if its string value is equal to {@code paramName}. In
+ * other cases null.
+ */
+ private static <T> T parseEnumTypeParameter(final ContainerNode value, final Class<T> classDescriptor,
+ final String paramName) {
+ final Optional<DataContainerChild> optAugNode = value.findChildByArg(SAL_REMOTE_AUG_IDENTIFIER);
+ if (optAugNode.isEmpty()) {
+ return null;
+ }
+ final DataContainerChild augNode = optAugNode.get();
+ if (!(augNode instanceof AugmentationNode)) {
+ return null;
+ }
+ final Optional<DataContainerChild> enumNode = ((AugmentationNode) augNode).findChildByArg(
+ new NodeIdentifier(QName.create(SAL_REMOTE_AUGMENT, paramName)));
+ if (enumNode.isEmpty()) {
+ return null;
+ }
+ final Object rawValue = enumNode.get().body();
+ if (!(rawValue instanceof String)) {
+ return null;
+ }
+
+ return resolveAsEnum(classDescriptor, (String) rawValue);
+ }
+
+ /**
+ * Checks whether {@code value} is one of the string representation of
+ * enumeration {@code classDescriptor}.
+ *
+ * @return enum object if string value of {@code classDescriptor}
+ * enumeration is equal to {@code value}. Other cases null.
+ */
+ private static <T> T parserURIEnumParameter(final Class<T> classDescriptor, final String value) {
+ if (Strings.isNullOrEmpty(value)) {
+ return null;
+ }
+ return resolveAsEnum(classDescriptor, value);
+ }
+
+ private static <T> T resolveAsEnum(final Class<T> classDescriptor, final String value) {
+ final T[] enumConstants = classDescriptor.getEnumConstants();
+ if (enumConstants != null) {
+ for (final T enm : classDescriptor.getEnumConstants()) {
+ if (((Enum<?>) enm).name().equals(value)) {
+ return enm;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static Map<String, String> resolveValuesFromUri(final String uri) {
+ final Map<String, String> result = new HashMap<>();
+ final String[] tokens = uri.split("/");
+ for (int i = 1; i < tokens.length; i++) {
+ final String[] parameterTokens = tokens[i].split("=");
+ if (parameterTokens.length == 2) {
+ result.put(parameterTokens[0], parameterTokens[1]);
+ }
+ }
+ return result;
+ }
+
+ private MapNode makeModuleMapNode(final Collection<? extends Module> modules) {
+ requireNonNull(modules);
+ final Module restconfModule = getRestconfModule();
+ final DataSchemaNode moduleSchemaNode = controllerContext
+ .getRestconfModuleRestConfSchemaNode(restconfModule, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
+ checkState(moduleSchemaNode instanceof ListSchemaNode);
+
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> listModuleBuilder =
+ SchemaAwareBuilders.mapBuilder((ListSchemaNode) moduleSchemaNode);
+
+ for (final Module module : modules) {
+ listModuleBuilder.withChild(toModuleEntryNode(module, moduleSchemaNode));
+ }
+ return listModuleBuilder.build();
+ }
+
+ private static MapEntryNode toModuleEntryNode(final Module module, final DataSchemaNode moduleSchemaNode) {
+ checkArgument(moduleSchemaNode instanceof ListSchemaNode,
+ "moduleSchemaNode has to be of type ListSchemaNode");
+ final ListSchemaNode listModuleSchemaNode = (ListSchemaNode) moduleSchemaNode;
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> moduleNodeValues =
+ SchemaAwareBuilders.mapEntryBuilder(listModuleSchemaNode);
+
+ var instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listModuleSchemaNode, "name");
+ final LeafSchemaNode nameSchemaNode = getFirstLeaf(instanceDataChildrenByName);
+ moduleNodeValues.withChild(
+ SchemaAwareBuilders.leafBuilder(nameSchemaNode).withValue(module.getName()).build());
+
+ final QNameModule qNameModule = module.getQNameModule();
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listModuleSchemaNode, "revision");
+ final LeafSchemaNode revisionSchemaNode = getFirstLeaf(instanceDataChildrenByName);
+ final Optional<Revision> revision = qNameModule.getRevision();
+ moduleNodeValues.withChild(SchemaAwareBuilders.leafBuilder(revisionSchemaNode)
+ .withValue(revision.map(Revision::toString).orElse("")).build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listModuleSchemaNode, "namespace");
+ final LeafSchemaNode namespaceSchemaNode = getFirstLeaf(instanceDataChildrenByName);
+ moduleNodeValues.withChild(SchemaAwareBuilders.leafBuilder(namespaceSchemaNode)
+ .withValue(qNameModule.getNamespace().toString()).build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listModuleSchemaNode, "feature");
+ final LeafListSchemaNode featureSchemaNode = getFirst(instanceDataChildrenByName, LeafListSchemaNode.class);
+ final ListNodeBuilder<Object, SystemLeafSetNode<Object>> featuresBuilder =
+ SchemaAwareBuilders.leafSetBuilder(featureSchemaNode);
+ for (final FeatureDefinition feature : module.getFeatures()) {
+ featuresBuilder.withChild(SchemaAwareBuilders.leafSetEntryBuilder(featureSchemaNode)
+ .withValue(feature.getQName().getLocalName()).build());
+ }
+ moduleNodeValues.withChild(featuresBuilder.build());
+
+ return moduleNodeValues.build();
+ }
+
+ protected MapEntryNode toStreamEntryNode(final String streamName, final DataSchemaNode streamSchemaNode) {
+ checkArgument(streamSchemaNode instanceof ListSchemaNode,
+ "streamSchemaNode has to be of type ListSchemaNode");
+ final ListSchemaNode listStreamSchemaNode = (ListSchemaNode) streamSchemaNode;
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamNodeValues =
+ SchemaAwareBuilders.mapEntryBuilder(listStreamSchemaNode);
+
+ var instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "name");
+ final LeafSchemaNode nameSchemaNode = getFirstLeaf(instanceDataChildrenByName);
+ streamNodeValues.withChild(
+ SchemaAwareBuilders.leafBuilder(nameSchemaNode).withValue(streamName).build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "description");
+ final LeafSchemaNode descriptionSchemaNode = getFirstLeaf(instanceDataChildrenByName);
+ streamNodeValues.withChild(SchemaAwareBuilders.leafBuilder(descriptionSchemaNode)
+ .withValue("DESCRIPTION_PLACEHOLDER")
+ .build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "replay-support");
+ final LeafSchemaNode replaySupportSchemaNode = getFirstLeaf(instanceDataChildrenByName);
+ streamNodeValues.withChild(SchemaAwareBuilders.leafBuilder(replaySupportSchemaNode)
+ .withValue(Boolean.TRUE).build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "replay-log-creation-time");
+ final LeafSchemaNode replayLogCreationTimeSchemaNode = getFirstLeaf(instanceDataChildrenByName);
+ streamNodeValues.withChild(
+ SchemaAwareBuilders.leafBuilder(replayLogCreationTimeSchemaNode).withValue("").build());
+
+ instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "events");
+ final LeafSchemaNode eventsSchemaNode = getFirstLeaf(instanceDataChildrenByName);
+ streamNodeValues.withChild(
+ SchemaAwareBuilders.leafBuilder(eventsSchemaNode).withValue(Empty.value()).build());
+
+ return streamNodeValues.build();
+ }
+
+ /**
+ * Prepare stream for notification.
+ *
+ * @param payload
+ * contains list of qnames of notifications
+ * @return - checked future object
+ */
+ private ListenableFuture<DOMRpcResult> invokeSalRemoteRpcNotifiStrRPC(final NormalizedNodeContext payload) {
+ final ContainerNode data = (ContainerNode) payload.getData();
+ LeafSetNode leafSet = null;
+ String outputType = "XML";
+ for (final DataContainerChild dataChild : data.body()) {
+ if (dataChild instanceof LeafSetNode) {
+ leafSet = (LeafSetNode) dataChild;
+ } else if (dataChild instanceof AugmentationNode) {
+ outputType = (String) ((AugmentationNode) dataChild).body().iterator().next().body();
+ }
+ }
+
+ final Collection<LeafSetEntryNode<?>> entryNodes = leafSet.body();
+ final List<Absolute> paths = new ArrayList<>();
+
+ StringBuilder streamNameBuilder = new StringBuilder(CREATE_NOTIFICATION_STREAM).append('/');
+ final Iterator<LeafSetEntryNode<?>> iterator = entryNodes.iterator();
+ while (iterator.hasNext()) {
+ final QName valueQName = QName.create((String) iterator.next().body());
+ final XMLNamespace namespace = valueQName.getModule().getNamespace();
+ final Module module = controllerContext.findModuleByNamespace(namespace);
+ checkNotNull(module, "Module for namespace %s does not exist", namespace);
+ NotificationDefinition notifiDef = null;
+ for (final NotificationDefinition notification : module.getNotifications()) {
+ if (notification.getQName().equals(valueQName)) {
+ notifiDef = notification;
+ break;
+ }
+ }
+ final String moduleName = module.getName();
+ if (notifiDef == null) {
+ throw new IllegalArgumentException("Notification " + valueQName + " does not exist in module "
+ + moduleName);
+ }
+
+ paths.add(Absolute.of(notifiDef.getQName()));
+ streamNameBuilder.append(moduleName).append(':').append(valueQName.getLocalName());
+ if (iterator.hasNext()) {
+ streamNameBuilder.append(',');
+ }
+ }
+
+ final String streamName = streamNameBuilder.toString();
+ final QName rpcQName = payload.getInstanceIdentifierContext().getSchemaNode().getQName();
+
+ if (!Notificator.existNotificationListenerFor(streamName)) {
+ Notificator.createNotificationListener(paths, streamName, outputType, controllerContext);
+ }
+
+ return Futures.immediateFuture(new DefaultDOMRpcResult(Builders.containerBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create(rpcQName, "output")))
+ .withChild(ImmutableNodes.leafNode(QName.create(rpcQName, "notification-stream-identifier"), streamName))
+ .build()));
+ }
+
+ private static LeafSchemaNode getFirstLeaf(final List<FoundChild> children) {
+ return getFirst(children, LeafSchemaNode.class);
+ }
+
+ private static <T extends DataSchemaNode> T getFirst(final List<FoundChild> children, final Class<T> expected) {
+ checkState(!children.isEmpty());
+ final var first = children.get(0);
+ checkState(expected.isInstance(first.child));
+ return expected.cast(first.child);
+ }
+
+ private static EffectiveModelContext modelContext(final DOMMountPoint mountPoint) {
+ return mountPoint.getService(DOMSchemaService.class)
+ .flatMap(svc -> Optional.ofNullable(svc.getGlobalContext()))
+ .orElse(null);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfProviderImpl.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfProviderImpl.java
new file mode 100644
index 0000000..5b6608e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfProviderImpl.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import java.math.BigInteger;
+import org.opendaylight.controller.md.sal.common.util.jmx.AbstractMXBean;
+import org.opendaylight.netconf.sal.rest.api.RestConnector;
+import org.opendaylight.netconf.sal.restconf.impl.jmx.Config;
+import org.opendaylight.netconf.sal.restconf.impl.jmx.Delete;
+import org.opendaylight.netconf.sal.restconf.impl.jmx.Get;
+import org.opendaylight.netconf.sal.restconf.impl.jmx.Operational;
+import org.opendaylight.netconf.sal.restconf.impl.jmx.Post;
+import org.opendaylight.netconf.sal.restconf.impl.jmx.Put;
+import org.opendaylight.netconf.sal.restconf.impl.jmx.RestConnectorRuntimeMXBean;
+import org.opendaylight.netconf.sal.restconf.impl.jmx.Rpcs;
+import org.opendaylight.netconf.sal.streams.websockets.WebSocketServer;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+
+public class RestconfProviderImpl extends AbstractMXBean
+ implements AutoCloseable, RestConnector, RestConnectorRuntimeMXBean {
+ private final IpAddress websocketAddress;
+ private final PortNumber websocketPort;
+ private final StatisticsRestconfServiceWrapper stats;
+ private Thread webSocketServerThread;
+
+ public RestconfProviderImpl(final StatisticsRestconfServiceWrapper stats, final IpAddress websocketAddress,
+ final PortNumber websocketPort) {
+ super("Draft02ProviderStatistics", "restconf-connector", null);
+ this.stats = requireNonNull(stats);
+ this.websocketAddress = requireNonNull(websocketAddress);
+ this.websocketPort = requireNonNull(websocketPort);
+ }
+
+ public void start() {
+ this.webSocketServerThread = new Thread(WebSocketServer.createInstance(
+ websocketAddress.stringValue(), websocketPort.getValue().toJava()));
+ this.webSocketServerThread.setName("Web socket server on port " + websocketPort);
+ this.webSocketServerThread.start();
+
+ registerMBean();
+ }
+
+ @Override
+ public void close() {
+ WebSocketServer.destroyInstance();
+ if (this.webSocketServerThread != null) {
+ this.webSocketServerThread.interrupt();
+ }
+
+ unregisterMBean();
+ }
+
+ @Override
+ public Config getConfig() {
+ final Config config = new Config();
+
+ final Get get = new Get();
+ get.setReceivedRequests(this.stats.getConfigGet());
+ get.setSuccessfulResponses(this.stats.getSuccessGetConfig());
+ get.setFailedResponses(this.stats.getFailureGetConfig());
+ config.setGet(get);
+
+ final Post post = new Post();
+ post.setReceivedRequests(this.stats.getConfigPost());
+ post.setSuccessfulResponses(this.stats.getSuccessPost());
+ post.setFailedResponses(this.stats.getFailurePost());
+ config.setPost(post);
+
+ final Put put = new Put();
+ put.setReceivedRequests(this.stats.getConfigPut());
+ put.setSuccessfulResponses(this.stats.getSuccessPut());
+ put.setFailedResponses(this.stats.getFailurePut());
+ config.setPut(put);
+
+ final Delete delete = new Delete();
+ delete.setReceivedRequests(this.stats.getConfigDelete());
+ delete.setSuccessfulResponses(this.stats.getSuccessDelete());
+ delete.setFailedResponses(this.stats.getFailureDelete());
+ config.setDelete(delete);
+
+ return config;
+ }
+
+ @Override
+ public Operational getOperational() {
+ final BigInteger opGet = this.stats.getOperationalGet();
+ final Operational operational = new Operational();
+ final Get get = new Get();
+ get.setReceivedRequests(opGet);
+ get.setSuccessfulResponses(this.stats.getSuccessGetOperational());
+ get.setFailedResponses(this.stats.getFailureGetOperational());
+ operational.setGet(get);
+ return operational;
+ }
+
+ @Override
+ public Rpcs getRpcs() {
+ final BigInteger rpcInvoke = this.stats.getRpc();
+ final Rpcs rpcs = new Rpcs();
+ rpcs.setReceivedRequests(rpcInvoke);
+ return rpcs;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/StatisticsRestconfServiceWrapper.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/StatisticsRestconfServiceWrapper.java
new file mode 100644
index 0000000..afe4be0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/StatisticsRestconfServiceWrapper.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import java.math.BigInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+
+@Singleton
+public final class StatisticsRestconfServiceWrapper implements RestconfService {
+
+ AtomicLong operationalGet = new AtomicLong();
+ AtomicLong configGet = new AtomicLong();
+ AtomicLong rpc = new AtomicLong();
+ AtomicLong configPost = new AtomicLong();
+ AtomicLong configPut = new AtomicLong();
+ AtomicLong configDelete = new AtomicLong();
+ AtomicLong successGetConfig = new AtomicLong();
+ AtomicLong successGetOperational = new AtomicLong();
+ AtomicLong successPost = new AtomicLong();
+ AtomicLong successPut = new AtomicLong();
+ AtomicLong successDelete = new AtomicLong();
+ AtomicLong failureGetConfig = new AtomicLong();
+ AtomicLong failureGetOperational = new AtomicLong();
+ AtomicLong failurePost = new AtomicLong();
+ AtomicLong failurePut = new AtomicLong();
+ AtomicLong failureDelete = new AtomicLong();
+
+ private final RestconfService delegate;
+
+ @Inject
+ public StatisticsRestconfServiceWrapper(final RestconfImpl delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * Factory method.
+ *
+ * @deprecated Just use {@link #StatisticsRestconfServiceWrapper(RestconfImpl)} constructor instead.
+ */
+ @Deprecated
+ public static StatisticsRestconfServiceWrapper newInstance(RestconfImpl delegate) {
+ return new StatisticsRestconfServiceWrapper(delegate);
+ }
+
+ @Override
+ public Object getRoot() {
+ return this.delegate.getRoot();
+ }
+
+ @Override
+ public NormalizedNodeContext getModules(final UriInfo uriInfo) {
+ return this.delegate.getModules(uriInfo);
+ }
+
+ @Override
+ public NormalizedNodeContext getModules(final String identifier, final UriInfo uriInfo) {
+ return this.delegate.getModules(identifier, uriInfo);
+ }
+
+ @Override
+ public NormalizedNodeContext getModule(final String identifier, final UriInfo uriInfo) {
+ return this.delegate.getModule(identifier, uriInfo);
+ }
+
+ @Override
+ public String getOperationsJSON() {
+ return this.delegate.getOperationsJSON();
+ }
+
+ @Override
+ public String getOperationsXML() {
+ return this.delegate.getOperationsXML();
+ }
+
+ @Override
+ public NormalizedNodeContext getOperations(final String identifier, final UriInfo uriInfo) {
+ return this.delegate.getOperations(identifier, uriInfo);
+ }
+
+ @Override
+ public NormalizedNodeContext invokeRpc(final String identifier, final NormalizedNodeContext payload,
+ final UriInfo uriInfo) {
+ this.rpc.incrementAndGet();
+ return this.delegate.invokeRpc(identifier, payload, uriInfo);
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public NormalizedNodeContext readConfigurationData(final String identifier, final UriInfo uriInfo) {
+ this.configGet.incrementAndGet();
+ NormalizedNodeContext normalizedNodeContext = null;
+ try {
+ normalizedNodeContext = this.delegate.readConfigurationData(identifier, uriInfo);
+ if (normalizedNodeContext.getData() != null) {
+ this.successGetConfig.incrementAndGet();
+ } else {
+ this.failureGetConfig.incrementAndGet();
+ }
+ } catch (final Exception e) {
+ this.failureGetConfig.incrementAndGet();
+ throw e;
+ }
+ return normalizedNodeContext;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public NormalizedNodeContext readOperationalData(final String identifier, final UriInfo uriInfo) {
+ this.operationalGet.incrementAndGet();
+ NormalizedNodeContext normalizedNodeContext = null;
+ try {
+ normalizedNodeContext = this.delegate.readOperationalData(identifier, uriInfo);
+ if (normalizedNodeContext.getData() != null) {
+ this.successGetOperational.incrementAndGet();
+ } else {
+ this.failureGetOperational.incrementAndGet();
+ }
+ } catch (final Exception e) {
+ this.failureGetOperational.incrementAndGet();
+ throw e;
+ }
+ return normalizedNodeContext;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public Response updateConfigurationData(final String identifier, final NormalizedNodeContext payload,
+ final UriInfo uriInfo) {
+ this.configPut.incrementAndGet();
+ Response response = null;
+ try {
+ response = this.delegate.updateConfigurationData(identifier, payload, uriInfo);
+ if (response.getStatus() == Status.OK.getStatusCode()) {
+ this.successPut.incrementAndGet();
+ } else {
+ this.failurePut.incrementAndGet();
+ }
+ } catch (final Exception e) {
+ this.failurePut.incrementAndGet();
+ throw e;
+ }
+ return response;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public Response createConfigurationData(final String identifier, final NormalizedNodeContext payload,
+ final UriInfo uriInfo) {
+ this.configPost.incrementAndGet();
+ Response response = null;
+ try {
+ response = this.delegate.createConfigurationData(identifier, payload, uriInfo);
+ if (response.getStatus() == Status.OK.getStatusCode()) {
+ this.successPost.incrementAndGet();
+ } else {
+ this.failurePost.incrementAndGet();
+ }
+ } catch (final Exception e) {
+ this.failurePost.incrementAndGet();
+ throw e;
+ }
+ return response;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public Response createConfigurationData(final NormalizedNodeContext payload, final UriInfo uriInfo) {
+ this.configPost.incrementAndGet();
+ Response response = null;
+ try {
+ response = this.delegate.createConfigurationData(payload, uriInfo);
+ if (response.getStatus() == Status.OK.getStatusCode()) {
+ this.successPost.incrementAndGet();
+ } else {
+ this.failurePost.incrementAndGet();
+ }
+ } catch (final Exception e) {
+ this.failurePost.incrementAndGet();
+ throw e;
+ }
+ return response;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ @Override
+ public Response deleteConfigurationData(final String identifier) {
+ this.configDelete.incrementAndGet();
+ Response response = null;
+ try {
+ response = this.delegate.deleteConfigurationData(identifier);
+ if (response.getStatus() == Status.OK.getStatusCode()) {
+ this.successDelete.incrementAndGet();
+ } else {
+ this.failureDelete.incrementAndGet();
+ }
+ } catch (final Exception e) {
+ this.failureDelete.incrementAndGet();
+ throw e;
+ }
+ return response;
+ }
+
+ @Override
+ public NormalizedNodeContext subscribeToStream(final String identifier, final UriInfo uriInfo) {
+ return this.delegate.subscribeToStream(identifier, uriInfo);
+ }
+
+ @Override
+ public NormalizedNodeContext getAvailableStreams(final UriInfo uriInfo) {
+ return this.delegate.getAvailableStreams(uriInfo);
+ }
+
+ @Override
+ public PatchStatusContext patchConfigurationData(final String identifier, final PatchContext payload,
+ final UriInfo uriInfo) {
+ return this.delegate.patchConfigurationData(identifier, payload, uriInfo);
+ }
+
+ @Override
+ public PatchStatusContext patchConfigurationData(final PatchContext payload, final UriInfo uriInfo) {
+ return this.delegate.patchConfigurationData(payload, uriInfo);
+ }
+
+ public BigInteger getConfigDelete() {
+ return BigInteger.valueOf(this.configDelete.get());
+ }
+
+ public BigInteger getConfigGet() {
+ return BigInteger.valueOf(this.configGet.get());
+ }
+
+ public BigInteger getConfigPost() {
+ return BigInteger.valueOf(this.configPost.get());
+ }
+
+ public BigInteger getConfigPut() {
+ return BigInteger.valueOf(this.configPut.get());
+ }
+
+ public BigInteger getOperationalGet() {
+ return BigInteger.valueOf(this.operationalGet.get());
+ }
+
+ public BigInteger getRpc() {
+ return BigInteger.valueOf(this.rpc.get());
+ }
+
+ public BigInteger getSuccessGetConfig() {
+ return BigInteger.valueOf(this.successGetConfig.get());
+ }
+
+ public BigInteger getSuccessGetOperational() {
+ return BigInteger.valueOf(this.successGetOperational.get());
+ }
+
+ public BigInteger getSuccessPost() {
+ return BigInteger.valueOf(this.successPost.get());
+ }
+
+ public BigInteger getSuccessPut() {
+ return BigInteger.valueOf(this.successPut.get());
+ }
+
+ public BigInteger getSuccessDelete() {
+ return BigInteger.valueOf(this.successDelete.get());
+ }
+
+ public BigInteger getFailureGetConfig() {
+ return BigInteger.valueOf(this.failureGetConfig.get());
+ }
+
+ public BigInteger getFailureGetOperational() {
+ return BigInteger.valueOf(this.failureGetOperational.get());
+ }
+
+ public BigInteger getFailurePost() {
+ return BigInteger.valueOf(this.failurePost.get());
+ }
+
+ public BigInteger getFailurePut() {
+ return BigInteger.valueOf(this.failurePut.get());
+ }
+
+ public BigInteger getFailureDelete() {
+ return BigInteger.valueOf(this.failureDelete.get());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Config.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Config.java
new file mode 100644
index 0000000..a115254
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Config.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017 Inocybe Technologies and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl.jmx;
+
+public class Config {
+ private Delete delete;
+
+ private Post post;
+
+ private Get get;
+
+ private Put put;
+
+ public Delete getDelete() {
+ return delete;
+ }
+
+ public void setDelete(Delete delete) {
+ this.delete = delete;
+ }
+
+ public Post getPost() {
+ return post;
+ }
+
+ public void setPost(Post post) {
+ this.post = post;
+ }
+
+ public Get getGet() {
+ return get;
+ }
+
+ public void setGet(Get get) {
+ this.get = get;
+ }
+
+ public Put getPut() {
+ return put;
+ }
+
+ public void setPut(Put put) {
+ this.put = put;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(delete, post, get, put);
+
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final Config that = (Config) obj;
+ if (!java.util.Objects.equals(delete, that.delete)) {
+ return false;
+ }
+
+ if (!java.util.Objects.equals(post, that.post)) {
+ return false;
+ }
+
+ if (!java.util.Objects.equals(get, that.get)) {
+ return false;
+ }
+
+ return java.util.Objects.equals(put, that.put);
+
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Delete.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Delete.java
new file mode 100644
index 0000000..16a815b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Delete.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017 Inocybe Technologies and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl.jmx;
+
+import java.math.BigInteger;
+
+public class Delete {
+ private BigInteger successfulResponses;
+
+ private BigInteger receivedRequests;
+
+ private BigInteger failedResponses;
+
+ public BigInteger getSuccessfulResponses() {
+ return successfulResponses;
+ }
+
+ public void setSuccessfulResponses(BigInteger successfulResponses) {
+ this.successfulResponses = successfulResponses;
+ }
+
+ public BigInteger getReceivedRequests() {
+ return receivedRequests;
+ }
+
+ public void setReceivedRequests(BigInteger receivedRequests) {
+ this.receivedRequests = receivedRequests;
+ }
+
+ public BigInteger getFailedResponses() {
+ return failedResponses;
+ }
+
+ public void setFailedResponses(BigInteger failedResponses) {
+ this.failedResponses = failedResponses;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(successfulResponses, receivedRequests, failedResponses);
+
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final Delete that = (Delete) obj;
+ if (!java.util.Objects.equals(successfulResponses, that.successfulResponses)) {
+ return false;
+ }
+
+ if (!java.util.Objects.equals(receivedRequests, that.receivedRequests)) {
+ return false;
+ }
+
+ return java.util.Objects.equals(failedResponses, that.failedResponses);
+
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Get.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Get.java
new file mode 100644
index 0000000..45603a8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Get.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 Inocybe Technologies and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl.jmx;
+
+import java.math.BigInteger;
+
+public class Get {
+ private BigInteger successfulResponses;
+
+ private BigInteger receivedRequests;
+
+ private BigInteger failedResponses;
+
+ public BigInteger getSuccessfulResponses() {
+ return successfulResponses;
+ }
+
+ public void setSuccessfulResponses(BigInteger successfulResponses) {
+ this.successfulResponses = successfulResponses;
+ }
+
+ public BigInteger getReceivedRequests() {
+ return receivedRequests;
+ }
+
+ public void setReceivedRequests(BigInteger receivedRequests) {
+ this.receivedRequests = receivedRequests;
+ }
+
+ public BigInteger getFailedResponses() {
+ return failedResponses;
+ }
+
+ public void setFailedResponses(BigInteger failedResponses) {
+ this.failedResponses = failedResponses;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(successfulResponses, receivedRequests, failedResponses);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final Get that = (Get) obj;
+ if (!java.util.Objects.equals(successfulResponses, that.successfulResponses)) {
+ return false;
+ }
+
+ if (!java.util.Objects.equals(receivedRequests, that.receivedRequests)) {
+ return false;
+ }
+
+ return java.util.Objects.equals(failedResponses, that.failedResponses);
+
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Operational.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Operational.java
new file mode 100644
index 0000000..5d9989b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Operational.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Inocybe Technologies and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl.jmx;
+
+public class Operational {
+ private Get get;
+
+ public Get getGet() {
+ return get;
+ }
+
+ public void setGet(Get get) {
+ this.get = get;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(get);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final Operational that = (Operational) obj;
+ return java.util.Objects.equals(get, that.get);
+
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Post.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Post.java
new file mode 100644
index 0000000..a466c01
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Post.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 Inocybe Technologies and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl.jmx;
+
+import java.math.BigInteger;
+
+public class Post {
+ private BigInteger successfulResponses;
+
+ private BigInteger receivedRequests;
+
+ private BigInteger failedResponses;
+
+ public BigInteger getSuccessfulResponses() {
+ return successfulResponses;
+ }
+
+ public void setSuccessfulResponses(BigInteger successfulResponses) {
+ this.successfulResponses = successfulResponses;
+ }
+
+ public BigInteger getReceivedRequests() {
+ return receivedRequests;
+ }
+
+ public void setReceivedRequests(BigInteger receivedRequests) {
+ this.receivedRequests = receivedRequests;
+ }
+
+ public BigInteger getFailedResponses() {
+ return failedResponses;
+ }
+
+ public void setFailedResponses(BigInteger failedResponses) {
+ this.failedResponses = failedResponses;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(successfulResponses, receivedRequests, failedResponses);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final Post that = (Post) obj;
+ if (!java.util.Objects.equals(successfulResponses, that.successfulResponses)) {
+ return false;
+ }
+
+ if (!java.util.Objects.equals(receivedRequests, that.receivedRequests)) {
+ return false;
+ }
+
+ return java.util.Objects.equals(failedResponses, that.failedResponses);
+
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Put.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Put.java
new file mode 100644
index 0000000..589f02c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Put.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017 Inocybe Technologies and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl.jmx;
+
+import java.math.BigInteger;
+
+public class Put {
+ private BigInteger successfulResponses;
+
+ private BigInteger receivedRequests;
+
+ private BigInteger failedResponses;
+
+ public BigInteger getSuccessfulResponses() {
+ return successfulResponses;
+ }
+
+ public void setSuccessfulResponses(BigInteger successfulResponses) {
+ this.successfulResponses = successfulResponses;
+ }
+
+ public BigInteger getReceivedRequests() {
+ return receivedRequests;
+ }
+
+ public void setReceivedRequests(BigInteger receivedRequests) {
+ this.receivedRequests = receivedRequests;
+ }
+
+ public BigInteger getFailedResponses() {
+ return failedResponses;
+ }
+
+ public void setFailedResponses(BigInteger failedResponses) {
+ this.failedResponses = failedResponses;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(successfulResponses, receivedRequests, failedResponses);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final Put that = (Put) obj;
+ if (!java.util.Objects.equals(successfulResponses, that.successfulResponses)) {
+ return false;
+ }
+
+ if (!java.util.Objects.equals(receivedRequests, that.receivedRequests)) {
+ return false;
+ }
+
+ return java.util.Objects.equals(failedResponses, that.failedResponses);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/RestConnectorRuntimeMXBean.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/RestConnectorRuntimeMXBean.java
new file mode 100644
index 0000000..cafcb8f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/RestConnectorRuntimeMXBean.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017 Inocybe Technologies and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl.jmx;
+
+public interface RestConnectorRuntimeMXBean {
+ Operational getOperational();
+
+ Rpcs getRpcs();
+
+ Config getConfig();
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Rpcs.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Rpcs.java
new file mode 100644
index 0000000..d849a4d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/Rpcs.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017 Inocybe Technologies and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl.jmx;
+
+import java.math.BigInteger;
+
+public class Rpcs {
+ private BigInteger successfulResponses;
+
+ private BigInteger receivedRequests;
+
+ private BigInteger failedResponses;
+
+ public BigInteger getSuccessfulResponses() {
+ return successfulResponses;
+ }
+
+ public void setSuccessfulResponses(BigInteger successfulResponses) {
+ this.successfulResponses = successfulResponses;
+ }
+
+ public BigInteger getReceivedRequests() {
+ return receivedRequests;
+ }
+
+ public void setReceivedRequests(BigInteger receivedRequests) {
+ this.receivedRequests = receivedRequests;
+ }
+
+ public BigInteger getFailedResponses() {
+ return failedResponses;
+ }
+
+ public void setFailedResponses(BigInteger failedResponses) {
+ this.failedResponses = failedResponses;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(successfulResponses, receivedRequests, failedResponses);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final Rpcs that = (Rpcs) obj;
+ if (!java.util.Objects.equals(successfulResponses, that.successfulResponses)) {
+ return false;
+ }
+
+ if (!java.util.Objects.equals(receivedRequests, that.receivedRequests)) {
+ return false;
+ }
+
+ return java.util.Objects.equals(failedResponses, that.failedResponses);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/package-info.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/package-info.java
new file mode 100644
index 0000000..d67ee37
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/jmx/package-info.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2017 Inocybe Technologies and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/**
+ * This package contains the statistical JMX classes for the Draft02 restconf implementation. Originally these classes
+ * were generated by the CSS code generator and were moved to this package on conversion to blueprint.
+ */
+package org.opendaylight.netconf.sal.restconf.impl.jmx;
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/package-info.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/package-info.java
new file mode 100644
index 0000000..e78fddd
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/package-info.java
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl; \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/web/WebInitializer.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/web/WebInitializer.java
new file mode 100644
index 0000000..d17c485
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/web/WebInitializer.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Inocybe Technologies and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.web;
+
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.servlet.ServletException;
+import org.opendaylight.aaa.filterchain.configuration.CustomFilterAdapterConfiguration;
+import org.opendaylight.aaa.filterchain.filters.CustomFilterAdapter;
+import org.opendaylight.aaa.web.FilterDetails;
+import org.opendaylight.aaa.web.ServletDetails;
+import org.opendaylight.aaa.web.WebContext;
+import org.opendaylight.aaa.web.WebContextBuilder;
+import org.opendaylight.aaa.web.WebContextRegistration;
+import org.opendaylight.aaa.web.WebContextSecurer;
+import org.opendaylight.aaa.web.WebServer;
+import org.opendaylight.aaa.web.servlet.ServletSupport;
+import org.opendaylight.netconf.sal.rest.impl.RestconfApplication;
+
+/**
+ * Initializes the bierman-02 endpoint.
+ *
+ * @author Thomas Pantelis
+ */
+@Singleton
+public class WebInitializer {
+
+ private final WebContextRegistration registration;
+
+ @Inject
+ public WebInitializer(final WebServer webServer, final WebContextSecurer webContextSecurer,
+ final ServletSupport servletSupport, final RestconfApplication webApp,
+ final CustomFilterAdapterConfiguration customFilterAdapterConfig) throws ServletException {
+
+ WebContextBuilder webContextBuilder = WebContext.builder().contextPath("restconf").supportsSessions(false)
+ .addServlet(ServletDetails.builder().servlet(servletSupport.createHttpServletBuilder(webApp).build())
+ .addUrlPattern("/*").build())
+
+ // Allows user to add javax.servlet.Filter(s) in front of REST services
+ .addFilter(FilterDetails.builder().filter(new CustomFilterAdapter(customFilterAdapterConfig))
+ .addUrlPattern("/*").build());
+
+ webContextSecurer.requireAuthentication(webContextBuilder, "/*");
+
+ registration = webServer.registerWebContext(webContextBuilder.build());
+ }
+
+ @PreDestroy
+ public void close() {
+ if (registration != null) {
+ registration.close();
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractCommonSubscriber.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractCommonSubscriber.java
new file mode 100644
index 0000000..76827d4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractCommonSubscriber.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import com.google.common.eventbus.AsyncEventBus;
+import com.google.common.eventbus.EventBus;
+import io.netty.channel.Channel;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Features of subscribing part of both notifications.
+ */
+abstract class AbstractCommonSubscriber extends AbstractQueryParams implements BaseListenerInterface {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractCommonSubscriber.class);
+
+ private final Set<Channel> subscribers = ConcurrentHashMap.newKeySet();
+ private final EventBus eventBus;
+
+ @SuppressWarnings("rawtypes")
+ private EventBusChangeRecorder eventBusChangeRecorder;
+ @SuppressWarnings("rawtypes")
+ private ListenerRegistration registration;
+
+ /**
+ * Creating {@link EventBus}.
+ */
+ protected AbstractCommonSubscriber() {
+ this.eventBus = new AsyncEventBus(Executors.newSingleThreadExecutor());
+ }
+
+ @Override
+ public final boolean hasSubscribers() {
+ return !this.subscribers.isEmpty();
+ }
+
+ @Override
+ public final Set<Channel> getSubscribers() {
+ return this.subscribers;
+ }
+
+ @Override
+ public final void close() {
+ if (registration != null) {
+ this.registration.close();
+ this.registration = null;
+ }
+
+ unregister();
+ }
+
+ /**
+ * Creates event of type {@link EventType#REGISTER}, set {@link Channel}
+ * subscriber to the event and post event into event bus.
+ *
+ * @param subscriber
+ * Channel
+ */
+ public void addSubscriber(final Channel subscriber) {
+ if (!subscriber.isActive()) {
+ LOG.debug("Channel is not active between websocket server and subscriber {}", subscriber.remoteAddress());
+ }
+ final Event event = new Event(EventType.REGISTER);
+ event.setSubscriber(subscriber);
+ this.eventBus.post(event);
+ }
+
+ /**
+ * Creates event of type {@link EventType#DEREGISTER}, sets {@link Channel}
+ * subscriber to the event and posts event into event bus.
+ *
+ * @param subscriber subscriber channel
+ */
+ public void removeSubscriber(final Channel subscriber) {
+ LOG.debug("Subscriber {} is removed.", subscriber.remoteAddress());
+ final Event event = new Event(EventType.DEREGISTER);
+ event.setSubscriber(subscriber);
+ this.eventBus.post(event);
+ }
+
+ /**
+ * Sets {@link ListenerRegistration} registration.
+ *
+ * @param registration
+ * DOMDataChangeListener registration
+ */
+ @SuppressWarnings("rawtypes")
+ public void setRegistration(final ListenerRegistration registration) {
+ this.registration = registration;
+ }
+
+ /**
+ * Checks if {@link ListenerRegistration} registration exist.
+ *
+ * @return True if exist, false otherwise.
+ */
+ public boolean isListening() {
+ return this.registration != null;
+ }
+
+ /**
+ * Creating and registering {@link EventBusChangeRecorder} of specific
+ * listener on {@link EventBus}.
+ *
+ * @param listener
+ * specific listener of notifications
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected <T extends BaseListenerInterface> void register(final T listener) {
+ this.eventBusChangeRecorder = new EventBusChangeRecorder(listener);
+ this.eventBus.register(this.eventBusChangeRecorder);
+ }
+
+ /**
+ * Post event to event bus.
+ *
+ * @param event
+ * data of incoming notifications
+ */
+ protected void post(final Event event) {
+ this.eventBus.post(event);
+ }
+
+ /**
+ * Removes all subscribers and unregisters event bus change recorder form
+ * event bus.
+ */
+ protected void unregister() {
+ this.subscribers.clear();
+ this.eventBus.unregister(this.eventBusChangeRecorder);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractNotificationsData.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractNotificationsData.java
new file mode 100644
index 0000000..7e7bc1a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractNotificationsData.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Abstract class for processing and preparing data.
+ *
+ */
+abstract class AbstractNotificationsData {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractNotificationsData.class);
+ private static final TransformerFactory TF = TransformerFactory.newInstance();
+ private static final XMLOutputFactory OF = XMLOutputFactory.newFactory();
+
+ /**
+ * Formats data specified by RFC3339.
+ *
+ * @param now time stamp
+ * @return Data specified by RFC3339.
+ */
+ protected static String toRFC3339(final Instant now) {
+ return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(OffsetDateTime.ofInstant(now, ZoneId.systemDefault()));
+ }
+
+ /**
+ * Creates {@link Document} document.
+ *
+ * @return {@link Document} document.
+ */
+ protected static Document createDocument() {
+ return UntrustedXML.newDocumentBuilder().newDocument();
+ }
+
+ /**
+ * Write normalized node to {@link DOMResult}.
+ *
+ * @param normalized
+ * data
+ * @param inference
+ * SchemaInferenceStack state for the data
+ * @return {@link DOMResult}
+ */
+ protected DOMResult writeNormalizedNode(final NormalizedNode normalized, final Inference inference)
+ throws IOException, XMLStreamException {
+ final Document doc = UntrustedXML.newDocumentBuilder().newDocument();
+ final DOMResult result = new DOMResult(doc);
+ NormalizedNodeWriter normalizedNodeWriter = null;
+ NormalizedNodeStreamWriter normalizedNodeStreamWriter = null;
+ XMLStreamWriter writer = null;
+
+ try {
+ writer = OF.createXMLStreamWriter(result);
+ normalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(writer, inference);
+ normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(normalizedNodeStreamWriter);
+
+ normalizedNodeWriter.write(normalized);
+
+ normalizedNodeWriter.flush();
+ } finally {
+ if (normalizedNodeWriter != null) {
+ normalizedNodeWriter.close();
+ }
+ if (normalizedNodeStreamWriter != null) {
+ normalizedNodeStreamWriter.close();
+ }
+ if (writer != null) {
+ writer.close();
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Generating base element of every notification.
+ *
+ * @param doc
+ * base {@link Document}
+ * @return element of {@link Document}
+ */
+ protected Element basePartDoc(final Document doc) {
+ final Element notificationElement =
+ doc.createElementNS("urn:ietf:params:xml:ns:netconf:notification:1.0", "notification");
+
+ doc.appendChild(notificationElement);
+
+ final Element eventTimeElement = doc.createElement("eventTime");
+ eventTimeElement.setTextContent(toRFC3339(Instant.now()));
+ notificationElement.appendChild(eventTimeElement);
+
+ return notificationElement;
+ }
+
+ /**
+ * Generating of {@link Document} transforming to string.
+ *
+ * @param doc
+ * {@link Document} with data
+ * @return - string from {@link Document}
+ */
+ protected String transformDoc(final Document doc) {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ try {
+ final Transformer transformer = TF.newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+ transformer.transform(new DOMSource(doc), new StreamResult(out));
+ } catch (final TransformerException e) {
+ // FIXME: this should raise an exception
+ final String msg = "Error during transformation of Document into String";
+ LOG.error(msg, e);
+ return msg;
+ }
+
+ return new String(out.toByteArray(), StandardCharsets.UTF_8);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractQueryParams.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractQueryParams.java
new file mode 100644
index 0000000..4697646
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/AbstractQueryParams.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.io.StringReader;
+import java.time.Instant;
+import java.util.Optional;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+
+/**
+ * Features of query parameters part of both notifications.
+ *
+ */
+abstract class AbstractQueryParams extends AbstractNotificationsData {
+ // FIXME: BUG-7956: switch to using UntrustedXML
+ private static final DocumentBuilderFactory DBF;
+
+ static {
+ final DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+ f.setCoalescing(true);
+ f.setExpandEntityReferences(false);
+ f.setIgnoringElementContentWhitespace(true);
+ f.setIgnoringComments(true);
+ f.setXIncludeAware(false);
+ try {
+ f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ f.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ } catch (final ParserConfigurationException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ DBF = f;
+ }
+
+ // FIXME: these should be final
+ private Instant start = null;
+ private Instant stop = null;
+ private String filter = null;
+ private boolean leafNodesOnly = false;
+ private boolean skipNotificationData = false;
+
+ @VisibleForTesting
+ public final Instant getStart() {
+ return start;
+ }
+
+ /**
+ * Set query parameters for listener.
+ *
+ * @param start
+ * start-time of getting notification
+ * @param stop
+ * stop-time of getting notification
+ * @param filter
+ * indicate which subset of all possible events are of interest
+ * @param leafNodesOnly
+ * if true, notifications will contain changes to leaf nodes only
+ * @param skipNotificationData
+ * if true, notification will not contain changed data
+ */
+ @SuppressWarnings("checkstyle:hiddenField")
+ public void setQueryParams(final Instant start, final Optional<Instant> stop, final Optional<String> filter,
+ final boolean leafNodesOnly, final boolean skipNotificationData) {
+ this.start = requireNonNull(start);
+ this.stop = stop.orElse(null);
+ this.filter = filter.orElse(null);
+ this.leafNodesOnly = leafNodesOnly;
+ this.skipNotificationData = skipNotificationData;
+ }
+
+ /**
+ * Check whether this query should only notify about leaf node changes.
+ *
+ * @return true if this query should only notify about leaf node changes
+ */
+ public boolean getLeafNodesOnly() {
+ return leafNodesOnly;
+ }
+
+ /**
+ * Check whether this query should notify changes without data.
+ *
+ * @return true if this query should notify about changes with data
+ */
+ public boolean isSkipNotificationData() {
+ return skipNotificationData;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ <T extends BaseListenerInterface> boolean checkStartStop(final Instant now, final T listener) {
+ if (this.stop != null) {
+ if (this.start.compareTo(now) < 0 && this.stop.compareTo(now) > 0) {
+ return true;
+ }
+ if (this.stop.compareTo(now) < 0) {
+ try {
+ listener.close();
+ } catch (final Exception e) {
+ throw new RestconfDocumentedException("Problem with unregister listener." + e);
+ }
+ }
+ } else if (this.start != null) {
+ if (this.start.compareTo(now) < 0) {
+ this.start = null;
+ return true;
+ }
+ } else {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check if is filter used and then prepare and post data do client.
+ *
+ * @param xml data of notification
+ */
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ boolean checkFilter(final String xml) {
+ if (this.filter == null) {
+ return true;
+ }
+
+ try {
+ return parseFilterParam(xml);
+ } catch (final Exception e) {
+ throw new RestconfDocumentedException("Problem while parsing filter.", e);
+ }
+ }
+
+ /**
+ * Parse and evaluate filter value by xml.
+ *
+ * @return true or false - depends on filter expression and data of
+ * notifiaction
+ * @throws Exception if operation fails
+ */
+ private boolean parseFilterParam(final String xml) throws Exception {
+ final Document docOfXml = DBF.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
+ final XPath xPath = XPathFactory.newInstance().newXPath();
+ // FIXME: BUG-7956: xPath.setNamespaceContext(nsContext);
+ return (boolean) xPath.compile(this.filter).evaluate(docOfXml, XPathConstants.BOOLEAN);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/BaseListenerInterface.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/BaseListenerInterface.java
new file mode 100644
index 0000000..4804e16
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/BaseListenerInterface.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import io.netty.channel.Channel;
+import java.util.Set;
+
+/**
+ * Base interface for both listeners({@link ListenerAdapter},
+ * {@link NotificationListenerAdapter}).
+ */
+interface BaseListenerInterface extends AutoCloseable {
+
+ /**
+ * Return all subscribers of listener.
+ *
+ * @return set of subscribers
+ */
+ Set<Channel> getSubscribers();
+
+ /**
+ * Checks if exists at least one {@link Channel} subscriber.
+ *
+ * @return True if exist at least one {@link Channel} subscriber, false
+ * otherwise.
+ */
+ boolean hasSubscribers();
+
+ /**
+ * Get name of stream.
+ *
+ * @return stream name
+ */
+ String getStreamName();
+
+ /**
+ * Get output type.
+ *
+ * @return outputType
+ */
+ String getOutputType();
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/Event.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/Event.java
new file mode 100644
index 0000000..486d807
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/Event.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import io.netty.channel.Channel;
+
+/**
+ * Represents event of specific {@link EventType} type, holds data and
+ * {@link Channel} subscriber.
+ */
+class Event {
+ private final EventType type;
+ private Channel subscriber;
+ private String data;
+
+ /**
+ * Creates new event specified by {@link EventType} type.
+ *
+ * @param type
+ * EventType
+ */
+ Event(final EventType type) {
+ this.type = type;
+ }
+
+ /**
+ * Gets the {@link Channel} subscriber.
+ *
+ * @return Channel
+ */
+ public Channel getSubscriber() {
+ return this.subscriber;
+ }
+
+ /**
+ * Sets subscriber for event.
+ *
+ * @param subscriber
+ * Channel
+ */
+ public void setSubscriber(final Channel subscriber) {
+ this.subscriber = subscriber;
+ }
+
+ /**
+ * Gets event String.
+ *
+ * @return String representation of event data.
+ */
+ public String getData() {
+ return this.data;
+ }
+
+ /**
+ * Sets event data.
+ *
+ * @param data
+ * String.
+ */
+ public void setData(final String data) {
+ this.data = data;
+ }
+
+ /**
+ * Gets event type.
+ *
+ * @return The type of the event.
+ */
+ public EventType getType() {
+ return this.type;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/EventBusChangeRecorder.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/EventBusChangeRecorder.java
new file mode 100644
index 0000000..11e5656
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/EventBusChangeRecorder.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import com.google.common.eventbus.Subscribe;
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class EventBusChangeRecorder<T extends BaseListenerInterface> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(EventBusChangeRecorder.class);
+ private final T listener;
+
+ /**
+ * Event bus change recorder of specific listener of notifications.
+ *
+ * @param listener
+ * specific listener
+ */
+ EventBusChangeRecorder(final T listener) {
+ this.listener = listener;
+ }
+
+ @Subscribe
+ public void recordCustomerChange(final Event event) {
+ if (event.getType() == EventType.REGISTER) {
+ final Channel subscriber = event.getSubscriber();
+ if (!this.listener.getSubscribers().contains(subscriber)) {
+ this.listener.getSubscribers().add(subscriber);
+ }
+ } else if (event.getType() == EventType.DEREGISTER) {
+ this.listener.getSubscribers().remove(event.getSubscriber());
+ Notificator.removeListenerIfNoSubscriberExists(this.listener);
+ } else if (event.getType() == EventType.NOTIFY) {
+ for (final Channel subscriber : this.listener.getSubscribers()) {
+ if (subscriber.isActive()) {
+ LOG.debug("Data are sent to subscriber {}:", subscriber.remoteAddress());
+ subscriber.writeAndFlush(new TextWebSocketFrame(event.getData()));
+ } else {
+ LOG.debug("Subscriber {} is removed - channel is not active yet.", subscriber.remoteAddress());
+ this.listener.getSubscribers().remove(subscriber);
+ }
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/EventType.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/EventType.java
new file mode 100644
index 0000000..ba7c2a3
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/EventType.java
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+/**
+ * Type of the event.
+ */
+enum EventType {
+ REGISTER, DEREGISTER, NOTIFY
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapter.java
new file mode 100644
index 0000000..fc85862
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapter.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2014, 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Optional;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.dom.DOMResult;
+import org.json.XML;
+import org.opendaylight.mdsal.dom.api.ClusteredDOMDataTreeChangeListener;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * {@link ListenerAdapter} is responsible to track events, which occurred by
+ * changing data in data source.
+ */
+public class ListenerAdapter extends AbstractCommonSubscriber implements ClusteredDOMDataTreeChangeListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapter.class);
+ private static final String DATA_CHANGE_EVENT = "data-change-event";
+ private static final String PATH = "path";
+ private static final String OPERATION = "operation";
+
+ private final ControllerContext controllerContext;
+ private final YangInstanceIdentifier path;
+ private final String streamName;
+ private final NotificationOutputType outputType;
+
+ /**
+ * Creates new {@link ListenerAdapter} listener specified by path and stream
+ * name and register for subscribing.
+ *
+ * @param path
+ * Path to data in data store.
+ * @param streamName
+ * The name of the stream.
+ * @param outputType
+ * Type of output on notification (JSON, XML)
+ */
+ @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR", justification = "non-final for testing")
+ ListenerAdapter(final YangInstanceIdentifier path, final String streamName,
+ final NotificationOutputType outputType, final ControllerContext controllerContext) {
+ this.outputType = requireNonNull(outputType);
+ this.path = requireNonNull(path);
+ checkArgument(streamName != null && !streamName.isEmpty());
+ this.streamName = streamName;
+ this.controllerContext = controllerContext;
+ register(this);
+ }
+
+ @Override
+ public void onInitialData() {
+ // No-op
+ }
+
+ @Override
+ public void onDataTreeChanged(final List<DataTreeCandidate> dataTreeCandidates) {
+ final Instant now = Instant.now();
+ if (!checkStartStop(now, this)) {
+ return;
+ }
+
+ final String xml = prepareXml(dataTreeCandidates);
+ if (checkFilter(xml)) {
+ prepareAndPostData(xml);
+ }
+ }
+
+ /**
+ * Gets the name of the stream.
+ *
+ * @return The name of the stream.
+ */
+ @Override
+ public String getStreamName() {
+ return streamName;
+ }
+
+ @Override
+ public String getOutputType() {
+ return outputType.getName();
+ }
+
+ /**
+ * Get path pointed to data in data store.
+ *
+ * @return Path pointed to data in data store.
+ */
+ public YangInstanceIdentifier getPath() {
+ return path;
+ }
+
+ /**
+ * Prepare data of notification and data to client.
+ *
+ * @param xml data
+ */
+ private void prepareAndPostData(final String xml) {
+ final Event event = new Event(EventType.NOTIFY);
+ if (outputType.equals(NotificationOutputType.JSON)) {
+ event.setData(XML.toJSONObject(xml).toString());
+ } else {
+ event.setData(xml);
+ }
+ post(event);
+ }
+
+ /**
+ * Tracks events of data change by customer.
+ */
+
+ /**
+ * Prepare data in printable form and transform it to String.
+ *
+ * @return Data in printable form.
+ */
+ private String prepareXml(final Collection<DataTreeCandidate> candidates) {
+ final EffectiveModelContext schemaContext = controllerContext.getGlobalSchema();
+ final DataSchemaContextTree dataContextTree = DataSchemaContextTree.from(schemaContext);
+ final Document doc = createDocument();
+ final Element notificationElement = basePartDoc(doc);
+
+ final Element dataChangedNotificationEventElement = doc.createElementNS(
+ "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "data-changed-notification");
+
+ addValuesToDataChangedNotificationEventElement(doc, dataChangedNotificationEventElement, candidates,
+ schemaContext, dataContextTree);
+ notificationElement.appendChild(dataChangedNotificationEventElement);
+ return transformDoc(doc);
+ }
+
+ /**
+ * Adds values to data changed notification event element.
+ *
+ * @param doc
+ * {@link Document}
+ * @param dataChangedNotificationEventElement
+ * {@link Element}
+ * @param dataTreeCandidates
+ * {@link DataTreeCandidate}
+ */
+ private void addValuesToDataChangedNotificationEventElement(final Document doc,
+ final Element dataChangedNotificationEventElement,
+ final Collection<DataTreeCandidate> dataTreeCandidates,
+ final EffectiveModelContext schemaContext, final DataSchemaContextTree dataSchemaContextTree) {
+
+ for (DataTreeCandidate dataTreeCandidate : dataTreeCandidates) {
+ DataTreeCandidateNode candidateNode = dataTreeCandidate.getRootNode();
+ if (candidateNode == null) {
+ continue;
+ }
+ YangInstanceIdentifier yiid = dataTreeCandidate.getRootPath();
+
+ boolean isSkipNotificationData = this.isSkipNotificationData();
+ if (isSkipNotificationData) {
+ createCreatedChangedDataChangeEventElementWithoutData(doc,
+ dataChangedNotificationEventElement, dataTreeCandidate.getRootNode());
+ } else {
+ addNodeToDataChangeNotificationEventElement(doc, dataChangedNotificationEventElement, candidateNode,
+ yiid.getParent(), schemaContext, dataSchemaContextTree);
+ }
+ }
+ }
+
+ private void addNodeToDataChangeNotificationEventElement(final Document doc,
+ final Element dataChangedNotificationEventElement, final DataTreeCandidateNode candidateNode,
+ final YangInstanceIdentifier parentYiid, final EffectiveModelContext schemaContext,
+ final DataSchemaContextTree dataSchemaContextTree) {
+
+ Optional<NormalizedNode> optionalNormalizedNode = Optional.empty();
+ switch (candidateNode.getModificationType()) {
+ case APPEARED:
+ case SUBTREE_MODIFIED:
+ case WRITE:
+ optionalNormalizedNode = candidateNode.getDataAfter();
+ break;
+ case DELETE:
+ case DISAPPEARED:
+ optionalNormalizedNode = candidateNode.getDataBefore();
+ break;
+ case UNMODIFIED:
+ default:
+ break;
+ }
+
+ if (optionalNormalizedNode.isEmpty()) {
+ LOG.error("No node present in notification for {}", candidateNode);
+ return;
+ }
+
+ NormalizedNode normalizedNode = optionalNormalizedNode.get();
+ YangInstanceIdentifier yiid = YangInstanceIdentifier.builder(parentYiid)
+ .append(normalizedNode.getIdentifier()).build();
+
+ boolean isNodeMixin = controllerContext.isNodeMixin(yiid);
+ boolean isSkippedNonLeaf = getLeafNodesOnly() && !(normalizedNode instanceof LeafNode);
+ if (!isNodeMixin && !isSkippedNonLeaf) {
+ Node node = null;
+ switch (candidateNode.getModificationType()) {
+ case APPEARED:
+ case SUBTREE_MODIFIED:
+ case WRITE:
+ Operation op = candidateNode.getDataBefore().isPresent() ? Operation.UPDATED : Operation.CREATED;
+ node = createCreatedChangedDataChangeEventElement(doc, yiid, normalizedNode, op,
+ schemaContext, dataSchemaContextTree);
+ break;
+ case DELETE:
+ case DISAPPEARED:
+ node = createDataChangeEventElement(doc, yiid, Operation.DELETED);
+ break;
+ case UNMODIFIED:
+ default:
+ break;
+ }
+ if (node != null) {
+ dataChangedNotificationEventElement.appendChild(node);
+ }
+ }
+
+ for (DataTreeCandidateNode childNode : candidateNode.getChildNodes()) {
+ addNodeToDataChangeNotificationEventElement(doc, dataChangedNotificationEventElement, childNode,
+ yiid, schemaContext, dataSchemaContextTree);
+ }
+ }
+
+ /**
+ * Creates changed event element from data.
+ *
+ * @param doc
+ * {@link Document}
+ * @param dataPath
+ * Path to data in data store.
+ * @param operation
+ * {@link Operation}
+ * @return {@link Node} node represented by changed event element.
+ */
+ private Node createDataChangeEventElement(final Document doc, final YangInstanceIdentifier dataPath,
+ final Operation operation) {
+ final Element dataChangeEventElement = doc.createElement(DATA_CHANGE_EVENT);
+ final Element pathElement = doc.createElement(PATH);
+ addPathAsValueToElement(dataPath, pathElement);
+ dataChangeEventElement.appendChild(pathElement);
+
+ final Element operationElement = doc.createElement(OPERATION);
+ operationElement.setTextContent(operation.value);
+ dataChangeEventElement.appendChild(operationElement);
+
+ return dataChangeEventElement;
+ }
+
+ /**
+ * Creates data change notification element without data element.
+ *
+ * @param doc
+ * {@link Document}
+ * @param dataChangedNotificationEventElement
+ * {@link Element}
+ * @param candidateNode
+ * {@link DataTreeCandidateNode}
+ */
+ private void createCreatedChangedDataChangeEventElementWithoutData(final Document doc,
+ final Element dataChangedNotificationEventElement, final DataTreeCandidateNode candidateNode) {
+ final Operation operation;
+ switch (candidateNode.getModificationType()) {
+ case APPEARED:
+ case SUBTREE_MODIFIED:
+ case WRITE:
+ operation = candidateNode.getDataBefore().isPresent() ? Operation.UPDATED : Operation.CREATED;
+ break;
+ case DELETE:
+ case DISAPPEARED:
+ operation = Operation.DELETED;
+ break;
+ case UNMODIFIED:
+ default:
+ return;
+ }
+ Node dataChangeEventElement = createDataChangeEventElement(doc, getPath(), operation);
+ dataChangedNotificationEventElement.appendChild(dataChangeEventElement);
+
+ }
+
+ private Node createCreatedChangedDataChangeEventElement(final Document doc,
+ final YangInstanceIdentifier eventPath, final NormalizedNode normalized, final Operation operation,
+ final EffectiveModelContext schemaContext, final DataSchemaContextTree dataSchemaContextTree) {
+ final Element dataChangeEventElement = doc.createElement(DATA_CHANGE_EVENT);
+ final Element pathElement = doc.createElement(PATH);
+ addPathAsValueToElement(eventPath, pathElement);
+ dataChangeEventElement.appendChild(pathElement);
+
+ final Element operationElement = doc.createElement(OPERATION);
+ operationElement.setTextContent(operation.value);
+ dataChangeEventElement.appendChild(operationElement);
+
+ final SchemaInferenceStack stack = dataSchemaContextTree.enterPath(eventPath).orElseThrow().stack();
+ if (!(normalized instanceof MapEntryNode) && !(normalized instanceof UnkeyedListEntryNode)
+ && !stack.isEmpty()) {
+ stack.exit();
+ }
+
+ final var inference = stack.toInference();
+
+ try {
+ final DOMResult domResult = writeNormalizedNode(normalized, inference);
+ final Node result = doc.importNode(domResult.getNode().getFirstChild(), true);
+ final Element dataElement = doc.createElement("data");
+ dataElement.appendChild(result);
+ dataChangeEventElement.appendChild(dataElement);
+ } catch (final IOException e) {
+ LOG.error("Error in writer ", e);
+ } catch (final XMLStreamException e) {
+ LOG.error("Error processing stream", e);
+ }
+
+ return dataChangeEventElement;
+ }
+
+ /**
+ * Adds path as value to element.
+ *
+ * @param dataPath
+ * Path to data in data store.
+ * @param element
+ * {@link Element}
+ */
+ @SuppressWarnings("rawtypes")
+ private void addPathAsValueToElement(final YangInstanceIdentifier dataPath, final Element element) {
+ final YangInstanceIdentifier normalizedPath = controllerContext.toXpathRepresentation(dataPath);
+ final StringBuilder textContent = new StringBuilder();
+
+ for (final PathArgument pathArgument : normalizedPath.getPathArguments()) {
+ if (pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier) {
+ continue;
+ }
+ textContent.append("/");
+ writeIdentifierWithNamespacePrefix(element, textContent, pathArgument.getNodeType());
+ if (pathArgument instanceof NodeIdentifierWithPredicates) {
+ for (final Entry<QName, Object> entry : ((NodeIdentifierWithPredicates) pathArgument).entrySet()) {
+ final QName keyValue = entry.getKey();
+ final String predicateValue = String.valueOf(entry.getValue());
+ textContent.append("[");
+ writeIdentifierWithNamespacePrefix(element, textContent, keyValue);
+ textContent.append("='");
+ textContent.append(predicateValue);
+ textContent.append("'");
+ textContent.append("]");
+ }
+ } else if (pathArgument instanceof NodeWithValue) {
+ textContent.append("[.='");
+ textContent.append(((NodeWithValue) pathArgument).getValue());
+ textContent.append("'");
+ textContent.append("]");
+ }
+ }
+ element.setTextContent(textContent.toString());
+ }
+
+ /**
+ * Writes identifier that consists of prefix and QName.
+ *
+ * @param element
+ * {@link Element}
+ * @param textContent
+ * StringBuilder
+ * @param qualifiedName
+ * QName
+ */
+ private void writeIdentifierWithNamespacePrefix(final Element element, final StringBuilder textContent,
+ final QName qualifiedName) {
+ final Module module = controllerContext.getGlobalSchema().findModule(qualifiedName.getModule())
+ .get();
+
+ textContent.append(module.getName());
+ textContent.append(":");
+ textContent.append(qualifiedName.getLocalName());
+ }
+
+ /**
+ * Consists of three types {@link Operation#CREATED},
+ * {@link Operation#UPDATED} and {@link Operation#DELETED}.
+ */
+ private enum Operation {
+ CREATED("created"), UPDATED("updated"), DELETED("deleted");
+
+ private final String value;
+
+ Operation(final String value) {
+ this.value = value;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerAdapter.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerAdapter.java
new file mode 100644
index 0000000..3061285
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerAdapter.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.time.Instant;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.dom.DOMResult;
+import org.opendaylight.mdsal.dom.api.DOMNotification;
+import org.opendaylight.mdsal.dom.api.DOMNotificationListener;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * {@link NotificationListenerAdapter} is responsible to track events on notifications.
+ */
+public final class NotificationListenerAdapter extends AbstractCommonSubscriber implements DOMNotificationListener {
+ private static final Logger LOG = LoggerFactory.getLogger(NotificationListenerAdapter.class);
+
+ private final ControllerContext controllerContext;
+ private final String streamName;
+ private final Absolute path;
+ private final String outputType;
+
+ /**
+ * Set path of listener and stream name, register event bus.
+ *
+ * @param path
+ * path of notification
+ * @param streamName
+ * stream name of listener
+ * @param outputType
+ * type of output on notification (JSON, XML)
+ */
+ NotificationListenerAdapter(final Absolute path, final String streamName, final String outputType,
+ final ControllerContext controllerContext) {
+ register(this);
+ this.outputType = requireNonNull(outputType);
+ this.path = requireNonNull(path);
+ checkArgument(streamName != null && !streamName.isEmpty());
+ this.streamName = streamName;
+ this.controllerContext = controllerContext;
+ }
+
+ /**
+ * Get outputType of listener.
+ *
+ * @return the outputType
+ */
+ @Override
+ public String getOutputType() {
+ return outputType;
+ }
+
+ @Override
+ public void onNotification(final DOMNotification notification) {
+ final Instant now = Instant.now();
+ if (!checkStartStop(now, this)) {
+ return;
+ }
+
+ final EffectiveModelContext schemaContext = controllerContext.getGlobalSchema();
+ final String xml = prepareXml(schemaContext, notification);
+ if (checkFilter(xml)) {
+ prepareAndPostData(outputType.equals("JSON") ? prepareJson(schemaContext, notification) : xml);
+ }
+ }
+
+ /**
+ * Get stream name of this listener.
+ *
+ * @return {@link String}
+ */
+ @Override
+ public String getStreamName() {
+ return streamName;
+ }
+
+ /**
+ * Get schema path of notification.
+ *
+ * @return {@link Absolute} SchemaNodeIdentifier
+ */
+ public Absolute getSchemaPath() {
+ return path;
+ }
+
+ /**
+ * Prepare data of notification and data to client.
+ *
+ * @param data data
+ */
+ private void prepareAndPostData(final String data) {
+ final Event event = new Event(EventType.NOTIFY);
+ event.setData(data);
+ post(event);
+ }
+
+ /**
+ * Prepare json from notification data.
+ *
+ * @return json as {@link String}
+ */
+ @VisibleForTesting
+ String prepareJson(final EffectiveModelContext schemaContext, final DOMNotification notification) {
+ final JsonObject json = new JsonObject();
+ json.add("ietf-restconf:notification", JsonParser.parseString(writeBodyToString(schemaContext, notification)));
+ json.addProperty("event-time", ListenerAdapter.toRFC3339(Instant.now()));
+ return json.toString();
+ }
+
+ private static String writeBodyToString(final EffectiveModelContext schemaContext,
+ final DOMNotification notification) {
+ final Writer writer = new StringWriter();
+ final NormalizedNodeStreamWriter jsonStream = JSONNormalizedNodeStreamWriter.createExclusiveWriter(
+ JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(schemaContext),
+ notification.getType(), null, JsonWriterFactory.createJsonWriter(writer));
+ final NormalizedNodeWriter nodeWriter = NormalizedNodeWriter.forStreamWriter(jsonStream);
+ try {
+ nodeWriter.write(notification.getBody());
+ nodeWriter.close();
+ } catch (final IOException e) {
+ throw new RestconfDocumentedException("Problem while writing body of notification to JSON. ", e);
+ }
+ return writer.toString();
+ }
+
+ private String prepareXml(final EffectiveModelContext schemaContext, final DOMNotification notification) {
+ final Document doc = createDocument();
+ final Element notificationElement = basePartDoc(doc);
+
+ final Element notificationEventElement = doc.createElementNS(
+ "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "create-notification-stream");
+ addValuesToNotificationEventElement(doc, notificationEventElement, schemaContext, notification);
+ notificationElement.appendChild(notificationEventElement);
+
+ return transformDoc(doc);
+ }
+
+ private void addValuesToNotificationEventElement(final Document doc, final Element element,
+ final EffectiveModelContext schemaContext, final DOMNotification notification) {
+ try {
+ final DOMResult domResult = writeNormalizedNode(notification.getBody(),
+ SchemaInferenceStack.of(schemaContext, path).toInference());
+ final Node result = doc.importNode(domResult.getNode().getFirstChild(), true);
+ final Element dataElement = doc.createElement("notification");
+ dataElement.appendChild(result);
+ element.appendChild(dataElement);
+ } catch (final IOException e) {
+ LOG.error("Error in writer ", e);
+ } catch (final XMLStreamException e) {
+ LOG.error("Error processing stream", e);
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/Notificator.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/Notificator.java
new file mode 100644
index 0000000..5bfa79f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/Notificator.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link Notificator} is responsible to create, remove and find
+ * {@link ListenerAdapter} listener.
+ */
+public final class Notificator {
+
+ private static Map<String, ListenerAdapter> dataChangeListener = new ConcurrentHashMap<>();
+ private static Map<String, List<NotificationListenerAdapter>> notificationListenersByStreamName =
+ new ConcurrentHashMap<>();
+
+ private static final Logger LOG = LoggerFactory.getLogger(Notificator.class);
+ private static final Lock LOCK = new ReentrantLock();
+
+ private Notificator() {
+ }
+
+ /**
+ * Returns list of all stream names.
+ */
+ public static Set<String> getStreamNames() {
+ return dataChangeListener.keySet();
+ }
+
+ /**
+ * Gets {@link ListenerAdapter} specified by stream name.
+ *
+ * @param streamName
+ * The name of the stream.
+ * @return {@link ListenerAdapter} specified by stream name.
+ */
+ public static ListenerAdapter getListenerFor(final String streamName) {
+ return dataChangeListener.get(streamName);
+ }
+
+ /**
+ * Checks if the listener specified by {@link YangInstanceIdentifier} path exist.
+ *
+ * @param streamName name of the stream
+ * @return True if the listener exist, false otherwise.
+ */
+ public static boolean existListenerFor(final String streamName) {
+ return dataChangeListener.containsKey(streamName);
+ }
+
+ /**
+ * Creates new {@link ListenerAdapter} listener from
+ * {@link YangInstanceIdentifier} path and stream name.
+ *
+ * @param path
+ * Path to data in data repository.
+ * @param streamName
+ * The name of the stream.
+ * @param outputType
+ * Spcific type of output for notifications - XML or JSON
+ * @return New {@link ListenerAdapter} listener from
+ * {@link YangInstanceIdentifier} path and stream name.
+ */
+ public static ListenerAdapter createListener(final YangInstanceIdentifier path, final String streamName,
+ final NotificationOutputType outputType, final ControllerContext controllerContext) {
+ final ListenerAdapter listener = new ListenerAdapter(path, streamName, outputType, controllerContext);
+ try {
+ LOCK.lock();
+ dataChangeListener.put(streamName, listener);
+ } finally {
+ LOCK.unlock();
+ }
+ return listener;
+ }
+
+ /**
+ * Looks for listener determined by {@link YangInstanceIdentifier} path and removes it.
+ * Creates String representation of stream name from URI. Removes slash from URI in start and end position.
+ *
+ * @param uri
+ * URI for creation stream name.
+ * @return String representation of stream name.
+ */
+ public static String createStreamNameFromUri(final String uri) {
+ if (uri == null) {
+ return null;
+ }
+ String result = uri;
+ if (result.startsWith("/")) {
+ result = result.substring(1);
+ }
+ if (result.endsWith("/")) {
+ result = result.substring(0, result.length() - 1);
+ }
+ return result;
+ }
+
+ /**
+ * Removes all listeners.
+ */
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public static void removeAllListeners() {
+ for (final ListenerAdapter listener : dataChangeListener.values()) {
+ try {
+ listener.close();
+ } catch (final Exception e) {
+ LOG.error("Failed to close listener", e);
+ }
+ }
+ try {
+ LOCK.lock();
+ dataChangeListener = new ConcurrentHashMap<>();
+ } finally {
+ LOCK.unlock();
+ }
+ }
+
+ /**
+ * Delete {@link ListenerAdapter} listener specified in parameter.
+ *
+ * @param <T>
+ *
+ * @param listener
+ * ListenerAdapter
+ */
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ private static <T extends BaseListenerInterface> void deleteListener(final T listener) {
+ if (listener != null) {
+ try {
+ listener.close();
+ } catch (final Exception e) {
+ LOG.error("Failed to close listener", e);
+ }
+ try {
+ LOCK.lock();
+ dataChangeListener.remove(listener.getStreamName());
+ } finally {
+ LOCK.unlock();
+ }
+ }
+ }
+
+ /**
+ * Check if the listener specified by qnames of request exist.
+ *
+ * @param streamName
+ * name of stream
+ * @return True if the listener exist, false otherwise.
+ */
+ public static boolean existNotificationListenerFor(final String streamName) {
+ return notificationListenersByStreamName.containsKey(streamName);
+ }
+
+ /**
+ * Prepare listener for notification ({@link NotificationDefinition}).
+ *
+ * @param paths
+ * paths of notifications
+ * @param streamName
+ * name of stream (generated by paths)
+ * @param outputType
+ * type of output for onNotification - XML or JSON
+ * @return List of {@link NotificationListenerAdapter} by paths
+ */
+ public static List<NotificationListenerAdapter> createNotificationListener(final List<Absolute> paths,
+ final String streamName, final String outputType, final ControllerContext controllerContext) {
+ final List<NotificationListenerAdapter> listListeners = new ArrayList<>();
+ for (final Absolute path : paths) {
+ final NotificationListenerAdapter listener =
+ new NotificationListenerAdapter(path, streamName, outputType, controllerContext);
+ listListeners.add(listener);
+ }
+ try {
+ LOCK.lock();
+ notificationListenersByStreamName.put(streamName, listListeners);
+ } finally {
+ LOCK.unlock();
+ }
+ return listListeners;
+ }
+
+ public static <T extends BaseListenerInterface> void removeListenerIfNoSubscriberExists(final T listener) {
+ if (!listener.hasSubscribers()) {
+ if (listener instanceof NotificationListenerAdapter) {
+ deleteNotificationListener(listener);
+ } else {
+ deleteListener(listener);
+ }
+ }
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ private static <T extends BaseListenerInterface> void deleteNotificationListener(final T listener) {
+ if (listener != null) {
+ try {
+ listener.close();
+ } catch (final Exception e) {
+ LOG.error("Failed to close listener", e);
+ }
+ try {
+ LOCK.lock();
+ notificationListenersByStreamName.remove(listener.getStreamName());
+ } finally {
+ LOCK.unlock();
+ }
+ }
+ }
+
+ public static List<NotificationListenerAdapter> getNotificationListenerFor(final String streamName) {
+ return notificationListenersByStreamName.get(streamName);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServer.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServer.java
new file mode 100644
index 0000000..a295c54
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServer.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.websockets;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link WebSocketServer} is the singleton responsible for starting and stopping the
+ * web socket server.
+ */
+public final class WebSocketServer implements Runnable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketServer.class);
+
+ private static final String DEFAULT_ADDRESS = "0.0.0.0";
+
+ private static WebSocketServer instance = null;
+
+ private final String address;
+ private final int port;
+
+ private EventLoopGroup bossGroup;
+ private EventLoopGroup workerGroup;
+
+
+ private WebSocketServer(final String address, final int port) {
+ this.address = address;
+ this.port = port;
+ }
+
+ /**
+ * Create singleton instance of {@link WebSocketServer}.
+ *
+ * @param port TCP port used for this server
+ * @return instance of {@link WebSocketServer}
+ */
+ private static WebSocketServer createInstance(final int port) {
+ instance = createInstance(DEFAULT_ADDRESS, port);
+ return instance;
+ }
+
+ public static WebSocketServer createInstance(final String address, final int port) {
+ checkState(instance == null, "createInstance() has already been called");
+ checkArgument(port >= 1024, "Privileged port (below 1024) is not allowed");
+
+ instance = new WebSocketServer(requireNonNull(address, "Address cannot be null."), port);
+ LOG.info("Created WebSocketServer on {}:{}", address, port);
+ return instance;
+ }
+
+ /**
+ * Get the websocket of TCP port.
+ *
+ * @return websocket TCP port
+ */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * Get instance of {@link WebSocketServer} created by {@link #createInstance(int)}.
+ *
+ * @return instance of {@link WebSocketServer}
+ */
+ public static WebSocketServer getInstance() {
+ return requireNonNull(instance, "createInstance() must be called prior to getInstance()");
+ }
+
+ /**
+ * Get instance of {@link WebSocketServer} created by {@link #createInstance(int)}.
+ * If an instance doesnt exist create one with the provided fallback port.
+ *
+ * @return instance of {@link WebSocketServer}
+ */
+ public static WebSocketServer getInstance(final int fallbackPort) {
+ if (instance != null) {
+ return instance;
+ }
+
+ LOG.warn("No instance for WebSocketServer found, creating one with a fallback port: {}", fallbackPort);
+ return createInstance(fallbackPort);
+ }
+
+ /**
+ * Destroy the existing instance.
+ */
+ public static void destroyInstance() {
+ checkState(instance != null, "createInstance() must be called prior to destroyInstance()");
+
+ instance.stop();
+ instance = null;
+ LOG.info("Destroyed WebSocketServer.");
+ }
+
+ @Override
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public void run() {
+ bossGroup = new NioEventLoopGroup();
+ workerGroup = new NioEventLoopGroup();
+ try {
+ final ServerBootstrap serverBootstrap = new ServerBootstrap();
+ serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
+ .childHandler(new WebSocketServerInitializer());
+
+ final Channel channel = serverBootstrap.bind(address, port).sync().channel();
+ LOG.info("Web socket server started at address {}, port {}.", address, port);
+
+ channel.closeFuture().sync();
+ } catch (final InterruptedException e) {
+ LOG.error("Web socket server encountered an error during startup attempt on port {}", port, e);
+ } catch (Throwable throwable) {
+ // sync() re-throws exceptions declared as Throwable, so the compiler doesn't see them
+ LOG.error("Error while binding to address {}, port {}", address, port, throwable);
+ throw throwable;
+ } finally {
+ stop();
+ }
+ }
+
+ /**
+ * Stops the web socket server and removes all listeners.
+ */
+ private void stop() {
+ LOG.info("Stopping the web socket server instance on port {}", port);
+ Notificator.removeAllListeners();
+ if (bossGroup != null) {
+ bossGroup.shutdownGracefully();
+ bossGroup = null;
+ }
+ if (workerGroup != null) {
+ workerGroup.shutdownGracefully();
+ workerGroup = null;
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServerHandler.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServerHandler.java
new file mode 100644
index 0000000..ed90e3f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServerHandler.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.websockets;
+
+import static io.netty.handler.codec.http.HttpHeaderNames.HOST;
+import static io.netty.handler.codec.http.HttpMethod.GET;
+import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
+import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
+import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
+import static io.netty.handler.codec.http.HttpResponseStatus.OK;
+import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;
+import static io.netty.handler.codec.http.HttpUtil.setContentLength;
+import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
+
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
+import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
+import io.netty.util.CharsetUtil;
+import java.util.List;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link WebSocketServerHandler} is implementation of {@link SimpleChannelInboundHandler} which allow handle
+ * {@link FullHttpRequest} and {@link WebSocketFrame} messages.
+ */
+public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketServerHandler.class);
+
+ private WebSocketServerHandshaker handshaker;
+
+ @Override
+ protected void channelRead0(final ChannelHandlerContext ctx, final Object msg) {
+ if (msg instanceof FullHttpRequest) {
+ handleHttpRequest(ctx, (FullHttpRequest) msg);
+ } else if (msg instanceof WebSocketFrame) {
+ handleWebSocketFrame(ctx, (WebSocketFrame) msg);
+ }
+ }
+
+ /**
+ * Checks if HTTP request method is GET and if is possible to decode HTTP result of request.
+ *
+ * @param ctx ChannelHandlerContext
+ * @param req FullHttpRequest
+ */
+ private void handleHttpRequest(final ChannelHandlerContext ctx, final FullHttpRequest req) {
+ // Handle a bad request.
+ if (!req.decoderResult().isSuccess()) {
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
+ return;
+ }
+
+ // Allow only GET methods.
+ if (req.method() != GET) {
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
+ return;
+ }
+
+ final String streamName = Notificator.createStreamNameFromUri(req.uri());
+ if (streamName.contains(RestconfImpl.DATA_SUBSCR)) {
+ final ListenerAdapter listener = Notificator.getListenerFor(streamName);
+ if (listener != null) {
+ listener.addSubscriber(ctx.channel());
+ LOG.debug("Subscriber successfully registered.");
+ } else {
+ LOG.error("Listener for stream with name '{}' was not found.", streamName);
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, INTERNAL_SERVER_ERROR));
+ }
+ } else if (streamName.contains(RestconfImpl.NOTIFICATION_STREAM)) {
+ final List<NotificationListenerAdapter> listeners = Notificator.getNotificationListenerFor(streamName);
+ if (listeners != null && !listeners.isEmpty()) {
+ for (final NotificationListenerAdapter listener : listeners) {
+ listener.addSubscriber(ctx.channel());
+ LOG.debug("Subscriber successfully registered.");
+ }
+ } else {
+ LOG.error("Listener for stream with name '{}' was not found.", streamName);
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, INTERNAL_SERVER_ERROR));
+ }
+ }
+
+ // Handshake
+ final WebSocketServerHandshakerFactory wsFactory =
+ new WebSocketServerHandshakerFactory(getWebSocketLocation(req),
+ null, false);
+ this.handshaker = wsFactory.newHandshaker(req);
+ if (this.handshaker == null) {
+ WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
+ } else {
+ this.handshaker.handshake(ctx.channel(), req);
+ }
+ }
+
+ /**
+ * Checks response status, send response and close connection if necessary.
+ *
+ * @param ctx ChannelHandlerContext
+ * @param req HttpRequest
+ * @param res FullHttpResponse
+ */
+ private static void sendHttpResponse(final ChannelHandlerContext ctx, final HttpRequest req,
+ final FullHttpResponse res) {
+ // Generate an error page if response getStatus code is not OK (200).
+ final boolean notOkay = !OK.equals(res.status());
+ if (notOkay) {
+ res.content().writeCharSequence(res.status().toString(), CharsetUtil.UTF_8);
+ setContentLength(res, res.content().readableBytes());
+ }
+
+ // Send the response and close the connection if necessary.
+ final ChannelFuture f = ctx.channel().writeAndFlush(res);
+ if (notOkay || !isKeepAlive(req)) {
+ f.addListener(ChannelFutureListener.CLOSE);
+ }
+ }
+
+ /**
+ * Handles web socket frame.
+ *
+ * @param ctx {@link ChannelHandlerContext}
+ * @param frame {@link WebSocketFrame}
+ */
+ private void handleWebSocketFrame(final ChannelHandlerContext ctx, final WebSocketFrame frame) {
+ if (frame instanceof CloseWebSocketFrame) {
+ this.handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
+ final String streamName = Notificator.createStreamNameFromUri(((CloseWebSocketFrame) frame).reasonText());
+ if (streamName.contains(RestconfImpl.DATA_SUBSCR)) {
+ final ListenerAdapter listener = Notificator.getListenerFor(streamName);
+ if (listener != null) {
+ listener.removeSubscriber(ctx.channel());
+ LOG.debug("Subscriber successfully registered.");
+
+ Notificator.removeListenerIfNoSubscriberExists(listener);
+ }
+ } else if (streamName.contains(RestconfImpl.NOTIFICATION_STREAM)) {
+ final List<NotificationListenerAdapter> listeners = Notificator.getNotificationListenerFor(streamName);
+ if (listeners != null && !listeners.isEmpty()) {
+ for (final NotificationListenerAdapter listener : listeners) {
+ listener.removeSubscriber(ctx.channel());
+ }
+ }
+ }
+ return;
+ } else if (frame instanceof PingWebSocketFrame) {
+ ctx.channel().writeAndFlush(new PongWebSocketFrame(frame.content().retain()));
+ return;
+ }
+ }
+
+ @Override
+ public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
+ ctx.close();
+ }
+
+ /**
+ * Get web socket location from HTTP request.
+ *
+ * @param req HTTP request from which the location will be returned
+ * @return String representation of web socket location.
+ */
+ private static String getWebSocketLocation(final HttpRequest req) {
+ return "ws://" + req.headers().get(HOST) + req.uri();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServerInitializer.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServerInitializer.java
new file mode 100644
index 0000000..365e982
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/websockets/WebSocketServerInitializer.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.sal.streams.websockets;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+
+/**
+ * {@link WebSocketServerInitializer} is used to setup the {@link ChannelPipeline} of a {@link io.netty.channel.Channel}
+ * .
+ */
+public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {
+
+ @Override
+ protected void initChannel(final SocketChannel ch) {
+ ChannelPipeline pipeline = ch.pipeline();
+ pipeline.addLast("codec-http", new HttpServerCodec());
+ pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
+ pipeline.addLast("handler", new WebSocketServerHandler());
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilder.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilder.java
new file mode 100644
index 0000000..42defe5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilder.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.DatastoreIdentifier.Enumeration;
+
+
+/**
+ **/
+public class DatastoreIdentifierBuilder {
+
+ public static DatastoreIdentifier getDefaultInstance(final String defaultValue) {
+ return new DatastoreIdentifier(Enumeration.valueOf(defaultValue));
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilder.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilder.java
new file mode 100644
index 0000000..dfd0aeb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilder.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules.Module.Revision;
+
+/**
+ * The purpose of generated class in src/main/java for Union types is to create
+ * new instances of unions from a string representation. In some cases it is
+ * very difficult to automate it since there can be unions such as (uint32 -
+ * uint16), or (string - uint32).
+ *
+ * The reason behind putting it under src/main/java is: This class is generated
+ * in form of a stub and needs to be finished by the user. This class is
+ * generated only once to prevent loss of user code.
+ *
+ */
+public class ModuleRevisionBuilder {
+
+ public static Revision getDefaultInstance(java.lang.String defaultValue) {
+ return RevisionBuilder.getDefaultInstance(defaultValue);
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilder.java b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilder.java
new file mode 100644
index 0000000..d09646a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilder.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules;
+
+import java.util.regex.Pattern;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.RevisionIdentifier;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules.Module.Revision;
+
+/**
+**/
+public class RevisionBuilder {
+
+ /**
+ * Defines the pattern for revisions. NOTE: This pattern will likely be
+ * updated in future versions of the ietf and should be adjusted accordingly
+ */
+ private static final Pattern REVISION_PATTERN = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
+
+ public static Revision getDefaultInstance(String defaultValue) {
+
+ if (defaultValue != null) {
+ if (REVISION_PATTERN.matcher(defaultValue).matches()) {
+ RevisionIdentifier id = new RevisionIdentifier(defaultValue);
+ return new Revision(id);
+ }
+ if (defaultValue.isEmpty()) {
+ return new Revision(defaultValue);
+ }
+ }
+
+ throw new IllegalArgumentException("Cannot create Revision from " + defaultValue
+ + ". Default value does not match pattern " + REVISION_PATTERN.pattern()
+ + " or empty string.");
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/resources/OSGI-INF/blueprint/restconf-config.xml b/netconf/restconf/restconf-nb-bierman02/src/main/resources/OSGI-INF/blueprint/restconf-config.xml
new file mode 100644
index 0000000..ab235e7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/resources/OSGI-INF/blueprint/restconf-config.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2017 Inocybe Technologies Inc. and others. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0">
+ <!-- Restconf providers -->
+ <cm:property-placeholder persistent-id="org.opendaylight.restconf" update-strategy="reload">
+ <cm:default-properties>
+ <cm:property name="websocket-address" value="0.0.0.0"/>
+ <cm:property name="websocket-port" value="8185"/>
+ </cm:default-properties>
+ </cm:property-placeholder>
+
+ <bean id="webSocketPort" class="org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber" factory-method="getDefaultInstance">
+ <argument value="${websocket-port}"/>
+ </bean>
+
+ <bean id="webSocketAddress" class="org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress">
+ <argument value="${websocket-address}"/>
+ </bean>
+
+ <bean id="restconfProviderDraft02" class="org.opendaylight.netconf.sal.restconf.impl.RestconfProviderImpl"
+ init-method="start" destroy-method="close">
+ <argument ref="statisticsRestconfServiceWrapper"/>
+ <argument ref="webSocketAddress"/>
+ <argument ref="webSocketPort"/>
+ </bean>
+
+ <bean id="brokerFacade" class="org.opendaylight.netconf.sal.restconf.impl.BrokerFacade" destroy-method="close">
+ <argument ref="dOMRpcService"/>
+ <argument ref="dOMDataBroker"/>
+ <argument ref="dOMNotificationService"/>
+ <argument ref="controllerContext"/>
+ </bean>
+ <bean id="controllerContext" class="org.opendaylight.netconf.sal.restconf.impl.ControllerContext" destroy-method="close">
+ <argument ref="dOMSchemaService"/>
+ <argument ref="dOMMountPointService"/>
+ <argument ref="dOMSchemaService"/>
+ </bean>
+ <bean id="jSONRestconfServiceImpl" class="org.opendaylight.netconf.sal.restconf.impl.JSONRestconfServiceImpl">
+ <argument ref="controllerContext"/>
+ <argument ref="restconfImpl"/>
+ </bean>
+ <bean id="restconfApplication" class="org.opendaylight.netconf.sal.rest.impl.RestconfApplication">
+ <argument ref="controllerContext"/>
+ <argument ref="statisticsRestconfServiceWrapper"/>
+ </bean>
+ <bean id="restconfImpl" class="org.opendaylight.netconf.sal.restconf.impl.RestconfImpl">
+ <argument ref="brokerFacade"/>
+ <argument ref="controllerContext"/>
+ </bean>
+ <bean id="statisticsRestconfServiceWrapper" class="org.opendaylight.netconf.sal.restconf.impl.StatisticsRestconfServiceWrapper">
+ <argument ref="restconfImpl"/>
+ </bean>
+ <bean id="webInitializer" class="org.opendaylight.netconf.sal.restconf.web.WebInitializer" destroy-method="close">
+ <argument ref="webServer"/>
+ <argument ref="webContextSecurer"/>
+ <argument ref="servletSupport"/>
+ <argument ref="restconfApplication"/>
+ <argument ref="customFilterAdapterConfiguration"/>
+ </bean>
+
+ <reference id="customFilterAdapterConfiguration" interface="org.opendaylight.aaa.filterchain.configuration.CustomFilterAdapterConfiguration"/>
+ <reference id="webContextSecurer" interface="org.opendaylight.aaa.web.WebContextSecurer"/>
+ <reference id="webServer" interface="org.opendaylight.aaa.web.WebServer"/>
+ <reference id="servletSupport" interface="org.opendaylight.aaa.web.servlet.ServletSupport"/>
+ <reference id="dOMDataBroker" interface="org.opendaylight.mdsal.dom.api.DOMDataBroker"/>
+ <reference id="dOMMountPointService" interface="org.opendaylight.mdsal.dom.api.DOMMountPointService"/>
+ <reference id="dOMNotificationService" interface="org.opendaylight.mdsal.dom.api.DOMNotificationService"/>
+ <reference id="dOMRpcService" interface="org.opendaylight.mdsal.dom.api.DOMRpcService"/>
+ <reference id="dOMSchemaService" interface="org.opendaylight.mdsal.dom.api.DOMSchemaService"/>
+ <service ref="jSONRestconfServiceImpl" interface="org.opendaylight.netconf.sal.restconf.api.JSONRestconfService"/>
+</blueprint>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/main/yang/ietf-restconf@2013-10-19.yang b/netconf/restconf/restconf-nb-bierman02/src/main/yang/ietf-restconf@2013-10-19.yang
new file mode 100644
index 0000000..83bb378
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/main/yang/ietf-restconf@2013-10-19.yang
@@ -0,0 +1,689 @@
+module ietf-restconf {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; revision-date 2013-07-15; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ container modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one module currently
+ supported by the server.";
+
+ leaf name {
+ type yang:yang-identifier;
+ description "The YANG module name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module revision date. An empty string is
+ used if no revision statement is present in the
+ YANG module.";
+ }
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server.";
+ }
+ leaf-list deviation {
+ type yang:yang-identifier;
+ description
+ "List of YANG deviation module names used by this
+ server to modify the conformance of the module
+ associated with this entry.";
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/md/sal/rest/common/TestRestconfUtils.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/md/sal/rest/common/TestRestconfUtils.java
new file mode 100644
index 0000000..d883797
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/md/sal/rest/common/TestRestconfUtils.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.rest.common;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.controller.sal.rest.impl.test.providers.TestJsonBodyWriter;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMMountPointService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public final class TestRestconfUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestRestconfUtils.class);
+
+ private TestRestconfUtils() {
+ throw new UnsupportedOperationException("Test utility class");
+ }
+
+ public static ControllerContext newControllerContext(final EffectiveModelContext schemaContext) {
+ return newControllerContext(schemaContext, null);
+ }
+
+ public static ControllerContext newControllerContext(final EffectiveModelContext schemaContext,
+ final DOMMountPoint mountInstance) {
+ final DOMMountPointService mockMountService = mock(DOMMountPointService.class);
+
+ if (mountInstance != null) {
+ doReturn(Optional.of(FixedDOMSchemaService.of(() -> schemaContext))).when(mountInstance)
+ .getService(eq(DOMSchemaService.class));
+ doReturn(Optional.ofNullable(mountInstance)).when(mockMountService).getMountPoint(
+ any(YangInstanceIdentifier.class));
+ }
+
+ DOMSchemaService mockSchemaService = mock(DOMSchemaService.class);
+ doReturn(schemaContext).when(mockSchemaService).getGlobalContext();
+
+ DOMSchemaService mockDomSchemaService = mock(DOMSchemaService.class);
+ doReturn(ImmutableClassToInstanceMap.of()).when(mockDomSchemaService).getExtensions();
+
+ return ControllerContext.newInstance(mockSchemaService, mockMountService, mockDomSchemaService);
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public static EffectiveModelContext loadSchemaContext(final String yangPath,
+ final EffectiveModelContext schemaContext) {
+ try {
+ Preconditions.checkArgument(yangPath != null, "Path can not be null.");
+ Preconditions.checkArgument(!yangPath.isEmpty(), "Path can not be empty.");
+ if (schemaContext == null) {
+ return YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles(yangPath));
+ } else {
+ throw new UnsupportedOperationException("Unable to add new yang sources to existing schema context.");
+ }
+ } catch (final Exception e) {
+ LOG.error("Yang files at path: " + yangPath + " weren't loaded.", e);
+ }
+ return schemaContext;
+ }
+
+ public static NormalizedNodeContext loadNormalizedContextFromJsonFile() {
+ throw new AbstractMethodError("Not implemented yet");
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public static NormalizedNodeContext loadNormalizedContextFromXmlFile(final String pathToInputFile,
+ final String uri, final ControllerContext controllerContext) {
+ final InstanceIdentifierContext iiContext = controllerContext.toInstanceIdentifier(uri);
+ final InputStream inputStream = TestJsonBodyWriter.class.getResourceAsStream(pathToInputFile);
+ try {
+ final Document doc = UntrustedXML.newDocumentBuilder().parse(inputStream);
+ final NormalizedNode nn = parse(iiContext, doc);
+ return new NormalizedNodeContext(iiContext, nn);
+ } catch (final Exception e) {
+ LOG.error("Load xml file " + pathToInputFile + " fail.", e);
+ }
+ return null;
+ }
+
+ private static NormalizedNode parse(final InstanceIdentifierContext iiContext, final Document doc)
+ throws XMLStreamException, IOException, SAXException, URISyntaxException {
+ final SchemaNode schemaNodeContext = iiContext.getSchemaNode();
+ final SchemaInferenceStack stack;
+ DataSchemaNode schemaNode = null;
+ if (schemaNodeContext instanceof RpcDefinition) {
+ final var rpc = (RpcDefinition) schemaNodeContext;
+ stack = SchemaInferenceStack.of(iiContext.getSchemaContext());
+ stack.enterSchemaTree(rpc.getQName());
+ if ("input".equalsIgnoreCase(doc.getDocumentElement().getLocalName())) {
+ schemaNode = rpc.getInput();
+ } else if ("output".equalsIgnoreCase(doc.getDocumentElement().getLocalName())) {
+ schemaNode = rpc.getOutput();
+ } else {
+ throw new IllegalStateException("Unknown Rpc input node");
+ }
+ stack.enterSchemaTree(schemaNode.getQName());
+ } else if (schemaNodeContext instanceof DataSchemaNode) {
+ schemaNode = (DataSchemaNode) schemaNodeContext;
+ stack = iiContext.inference().toSchemaInferenceStack();
+ } else {
+ throw new IllegalStateException("Unknow SchemaNode");
+ }
+
+ final String docRootElm = doc.getDocumentElement().getLocalName();
+ final String schemaNodeName = iiContext.getSchemaNode().getQName().getLocalName();
+
+ if (!schemaNodeName.equalsIgnoreCase(docRootElm)) {
+ for (final DataSchemaNode child : ((DataNodeContainer) schemaNode).getChildNodes()) {
+ if (child.getQName().getLocalName().equalsIgnoreCase(docRootElm)) {
+ schemaNode = child;
+ stack.enterSchemaTree(child.getQName());
+ break;
+ }
+ }
+ }
+
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, stack.toInference());
+
+ if (schemaNode instanceof ContainerLike || schemaNode instanceof ListSchemaNode) {
+ xmlParser.traverse(new DOMSource(doc.getDocumentElement()));
+ return resultHolder.getResult();
+ }
+ // FIXME : add another DataSchemaNode extensions e.g. LeafSchemaNode
+ return null;
+ }
+
+ public static Collection<File> loadFiles(final String resourceDirectory) throws FileNotFoundException {
+ final String path = TestRestconfUtils.class.getResource(resourceDirectory).getPath();
+ final File testDir = new File(path);
+ final String[] fileList = testDir.list();
+ final List<File> testFiles = new ArrayList<>();
+ if (fileList == null) {
+ throw new FileNotFoundException(resourceDirectory);
+ }
+ for (final String fileName : fileList) {
+ if (new File(testDir, fileName).isDirectory() == false) {
+ testFiles.add(new File(testDir, fileName));
+ }
+ }
+ return testFiles;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/InstanceIdentifierTypeLeafTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/InstanceIdentifierTypeLeafTest.java
new file mode 100644
index 0000000..3c46201
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/InstanceIdentifierTypeLeafTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class InstanceIdentifierTypeLeafTest {
+
+ @Test
+ public void stringToInstanceIdentifierTest() throws Exception {
+ final EffectiveModelContext schemaContext =
+ YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/instanceidentifier"));
+ ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ final InstanceIdentifierContext instanceIdentifier =
+ controllerContext.toInstanceIdentifier(
+ "/iid-value-module:cont-iid/iid-list/%2Fiid-value-module%3Acont-iid%2Fiid-value-module%3A"
+ + "values-iid%5Biid-value-module:value-iid='value'%5D");
+ final YangInstanceIdentifier yiD = instanceIdentifier.getInstanceIdentifier();
+ assertNotNull(yiD);
+ final PathArgument lastPathArgument = yiD.getLastPathArgument();
+ assertTrue(lastPathArgument.getNodeType().getNamespace().toString().equals("iid:value:module"));
+ assertTrue(lastPathArgument.getNodeType().getLocalName().equals("iid-list"));
+
+ final NodeIdentifierWithPredicates list = (NodeIdentifierWithPredicates) lastPathArgument;
+ final YangInstanceIdentifier value = (YangInstanceIdentifier) list.getValue(
+ QName.create(lastPathArgument.getNodeType(), "iid-leaf"));
+ final PathArgument lastPathArgumentOfValue = value.getLastPathArgument();
+ assertTrue(lastPathArgumentOfValue.getNodeType().getNamespace().toString().equals("iid:value:module"));
+ assertTrue(lastPathArgumentOfValue.getNodeType().getLocalName().equals("values-iid"));
+
+ final NodeIdentifierWithPredicates valueList = (NodeIdentifierWithPredicates) lastPathArgumentOfValue;
+ final String valueIid = (String) valueList.getValue(
+ QName.create(lastPathArgumentOfValue.getNodeType(), "value-iid"));
+ assertEquals("value", valueIid);
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java
new file mode 100644
index 0000000..5bbd161
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.URI;
+import java.util.List;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.netconf.sal.rest.api.RestconfConstants;
+import org.opendaylight.netconf.sal.rest.impl.AbstractIdentifierAwareJaxRsProvider;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public abstract class AbstractBodyReaderTest {
+ private static Field uriField;
+ private static Field requestField;
+
+ static {
+ try {
+ uriField = AbstractIdentifierAwareJaxRsProvider.class.getDeclaredField("uriInfo");
+ uriField.setAccessible(true);
+ requestField = AbstractIdentifierAwareJaxRsProvider.class.getDeclaredField("request");
+ requestField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected final ControllerContext controllerContext;
+ protected final MediaType mediaType;
+
+ protected AbstractBodyReaderTest(final EffectiveModelContext schemaContext, final DOMMountPoint mountInstance) {
+ mediaType = getMediaType();
+
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext, mountInstance);
+ }
+
+ protected abstract MediaType getMediaType();
+
+ protected static EffectiveModelContext schemaContextLoader(final String yangPath,
+ final EffectiveModelContext schemaContext) {
+ return TestRestconfUtils.loadSchemaContext(yangPath, schemaContext);
+ }
+
+ protected static <T extends AbstractIdentifierAwareJaxRsProvider> void mockBodyReader(
+ final String identifier, final T normalizedNodeProvider, final boolean isPost) throws Exception {
+ final UriInfo uriInfoMock = mock(UriInfo.class);
+ final MultivaluedMap<String, String> pathParm = new MultivaluedHashMap<>(1);
+
+ if (!identifier.isEmpty()) {
+ pathParm.put(RestconfConstants.IDENTIFIER, List.of(identifier));
+ }
+
+ when(uriInfoMock.getPathParameters()).thenReturn(pathParm);
+ when(uriInfoMock.getPathParameters(false)).thenReturn(pathParm);
+ when(uriInfoMock.getPathParameters(true)).thenReturn(pathParm);
+ when(uriInfoMock.getAbsolutePath()).thenReturn(URI.create("restconf"));
+ uriField.set(normalizedNodeProvider, uriInfoMock);
+
+ final Request request = mock(Request.class);
+ if (isPost) {
+ when(request.getMethod()).thenReturn("POST");
+ } else {
+ when(request.getMethod()).thenReturn("PUT");
+ }
+
+ requestField.set(normalizedNodeProvider, request);
+ }
+
+ protected static void checkMountPointNormalizedNodeContext(final NormalizedNodeContext nnContext) {
+ checkNormalizedNodeContext(nnContext);
+ assertNotNull(nnContext.getInstanceIdentifierContext().getMountPoint());
+ }
+
+ protected static void checkNormalizedNodeContext(final NormalizedNodeContext nnContext) {
+ assertNotNull(nnContext.getData());
+ assertNotNull(nnContext.getInstanceIdentifierContext().getInstanceIdentifier());
+ assertNotNull(nnContext.getInstanceIdentifierContext().getSchemaContext());
+ assertNotNull(nnContext.getInstanceIdentifierContext().getSchemaNode());
+ }
+
+ protected static void checkNormalizedNodeContextRpc(final NormalizedNodeContext nnContext) {
+ assertNotNull(nnContext.getData());
+ assertNull(nnContext.getInstanceIdentifierContext().getInstanceIdentifier());
+ assertNotNull(nnContext.getInstanceIdentifierContext().getSchemaContext());
+ assertNotNull(nnContext.getInstanceIdentifierContext().getSchemaNode());
+ }
+
+ protected static void checkPatchContext(final PatchContext patchContext) {
+ assertNotNull(patchContext.getData());
+ assertNotNull(patchContext.getInstanceIdentifierContext().getInstanceIdentifier());
+ assertNotNull(patchContext.getInstanceIdentifierContext().getSchemaContext());
+ assertNotNull(patchContext.getInstanceIdentifierContext().getSchemaNode());
+ }
+
+ protected static void checkPatchContextMountPoint(final PatchContext patchContext) {
+ checkPatchContext(patchContext);
+ assertNotNull(patchContext.getInstanceIdentifierContext().getMountPoint());
+ }
+
+ protected static EffectiveModelContext modelContext(final DOMMountPoint mountPoint) {
+ return mountPoint.getService(DOMSchemaService.class)
+ .flatMap(svc -> Optional.ofNullable(svc.getGlobalContext()))
+ .orElse(null);
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java
new file mode 100644
index 0000000..fe50c68
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.Set;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestJsonBodyReader extends AbstractBodyReaderTest {
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = QNameModule.create(
+ XMLNamespace.of("instance:identifier:module"), Revision.of("2014-01-17"));
+
+ public TestJsonBodyReader() {
+ super(schemaContext, null);
+ jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization()
+ throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName());
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, false);
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsondata.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerDataPutTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1");
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName);
+ final DataSchemaNode dataSchemaNodeOnPath = ((DataNodeContainer) dataSchemaNode).getDataChildByName(cont1QName);
+ final String uri = "instance-identifier-module:cont/cont1";
+ mockBodyReader(uri, jsonBodyReader, false);
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/json_sub_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNodeOnPath, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1");
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName);
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/json_sub_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerAugmentDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final Module augmentModule = schemaContext.findModules(XMLNamespace.of("augment:module")).iterator().next();
+ final QName contAugmentQName = QName.create(augmentModule.getQNameModule(), "cont-augment");
+ final AugmentationIdentifier augII = new AugmentationIdentifier(Set.of(contAugmentQName));
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName())
+ .node(augII).node(contAugmentQName);
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/json_augment_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ //FIXME: Uncomment this when JsonParserStream works correctly with case augmentation with choice
+ //@Test
+ public void moduleSubContainerChoiceAugmentDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final Module augmentModule = schemaContext.findModules(XMLNamespace.of("augment:module")).iterator().next();
+ final QName augmentChoice1QName = QName.create(augmentModule.getQNameModule(), "augment-choice1");
+ final QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
+ final QName containerQName = QName.create(augmentChoice1QName, "case-choice-case-container1");
+ final AugmentationIdentifier augChoice1II = new AugmentationIdentifier(Set.of(augmentChoice1QName));
+ final AugmentationIdentifier augChoice2II = new AugmentationIdentifier(Set.of(augmentChoice2QName));
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName())
+ .node(augChoice1II).node(augmentChoice1QName).node(augChoice2II).node(augmentChoice2QName)
+ .node(containerQName);
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/json_augment_choice_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "invoke-rpc-module:rpc-test";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream("/invoke-rpc/json/rpc-input.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null, null, null, mediaType, null,
+ inputStream);
+ checkNormalizedNodeContextRpc(returnValue);
+ final ContainerNode inputNode = (ContainerNode) returnValue.getData();
+ final YangInstanceIdentifier yangCont = YangInstanceIdentifier.of(
+ QName.create(inputNode.getIdentifier().getNodeType(), "cont"));
+ final Optional<DataContainerChild> contDataNode = inputNode.findChildByArg(yangCont.getLastPathArgument());
+ assertTrue(contDataNode.isPresent());
+ assertTrue(contDataNode.get() instanceof ContainerNode);
+ final YangInstanceIdentifier yangleaf = YangInstanceIdentifier.of(
+ QName.create(inputNode.getIdentifier().getNodeType(), "lf"));
+ final Optional<DataContainerChild> leafDataNode = ((ContainerNode) contDataNode.get())
+ .findChildByArg(yangleaf.getLastPathArgument());
+ assertTrue(leafDataNode.isPresent());
+ assertTrue("lf-test".equalsIgnoreCase(leafDataNode.get().body().toString()));
+ }
+
+ private static void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
+ final NormalizedNodeContext nnContext, final YangInstanceIdentifier dataNodeIdent) {
+ assertEquals(dataSchemaNode, nnContext.getInstanceIdentifierContext().getSchemaNode());
+ assertEquals(dataNodeIdent, nnContext.getInstanceIdentifierContext().getInstanceIdentifier());
+ assertNotNull(NormalizedNodes.findNode(nnContext.getData(), dataNodeIdent));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReaderMountPoint.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReaderMountPoint.java
new file mode 100644
index 0000000..e8776c8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReaderMountPoint.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestJsonBodyReaderMountPoint extends AbstractBodyReaderTest {
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = QNameModule.create(
+ XMLNamespace.of("instance:identifier:module"), Revision.of("2014-01-17"));
+
+ public TestJsonBodyReaderMountPoint() throws NoSuchFieldException, SecurityException {
+ super(schemaContext, mock(DOMMountPoint.class));
+ jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, false);
+ final InputStream inputStream = TestJsonBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/json/jsondata.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
+ }
+
+ @Test
+ public void moduleSubContainerDataPutTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont/cont1";
+ mockBodyReader(uri, jsonBodyReader, false);
+ final InputStream inputStream = TestJsonBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/json/json_sub_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue,
+ QName.create(dataSchemaNode.getQName(), "cont1"));
+ }
+
+ @Test
+ public void moduleSubContainerDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestJsonBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/json/json_sub_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/invoke-rpc-module:rpc-test";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestJsonBodyReaderMountPoint.class.getResourceAsStream(
+ "/invoke-rpc/json/rpc-input.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null, null, null, mediaType, null,
+ inputStream);
+ checkNormalizedNodeContextRpc(returnValue);
+ final ContainerNode inputNode = (ContainerNode) returnValue.getData();
+ final YangInstanceIdentifier yangCont = YangInstanceIdentifier.of(
+ QName.create(inputNode.getIdentifier().getNodeType(), "cont"));
+ final Optional<DataContainerChild> contDataNode = inputNode.findChildByArg(yangCont.getLastPathArgument());
+ assertTrue(contDataNode.isPresent());
+ assertTrue(contDataNode.get() instanceof ContainerNode);
+ final YangInstanceIdentifier yangleaf = YangInstanceIdentifier.of(
+ QName.create(inputNode.getIdentifier().getNodeType(), "lf"));
+ final Optional<DataContainerChild> leafDataNode =
+ ((ContainerNode) contDataNode.get()).findChildByArg(yangleaf.getLastPathArgument());
+ assertTrue(leafDataNode.isPresent());
+ assertTrue("lf-test".equalsIgnoreCase(leafDataNode.get().body().toString()));
+ }
+
+ private void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
+ final NormalizedNodeContext nnContext) {
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, nnContext, null);
+ }
+
+ protected void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
+ final NormalizedNodeContext nnContext, final QName qualifiedName) {
+ YangInstanceIdentifier dataNodeIdent = YangInstanceIdentifier.of(dataSchemaNode.getQName());
+ final DOMMountPoint mountPoint = nnContext.getInstanceIdentifierContext().getMountPoint();
+ final DataSchemaNode mountDataSchemaNode = modelContext(mountPoint).getDataChildByName(
+ dataSchemaNode.getQName());
+ assertNotNull(mountDataSchemaNode);
+ if (qualifiedName != null && dataSchemaNode instanceof DataNodeContainer) {
+ final DataSchemaNode child = ((DataNodeContainer) dataSchemaNode).getDataChildByName(qualifiedName);
+ dataNodeIdent = YangInstanceIdentifier.builder(dataNodeIdent).node(child.getQName()).build();
+ assertTrue(nnContext.getInstanceIdentifierContext().getSchemaNode().equals(child));
+ } else {
+ assertTrue(mountDataSchemaNode.equals(dataSchemaNode));
+ }
+ assertNotNull(NormalizedNodes.findNode(nnContext.getData(),
+ dataNodeIdent));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyWriter.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyWriter.java
new file mode 100644
index 0000000..121a7d6
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyWriter.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestJsonBodyWriter extends AbstractBodyReaderTest {
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private final NormalizedNodeJsonBodyWriter jsonBodyWriter;
+ private static EffectiveModelContext schemaContext;
+
+ public TestJsonBodyWriter() {
+ super(schemaContext, null);
+ this.jsonBodyWriter = new NormalizedNodeJsonBodyWriter();
+ this.jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "invoke-rpc-module:rpc-test";
+ mockBodyReader(uri, this.jsonBodyReader, true);
+ final InputStream inputStream = TestJsonBodyWriter.class
+ .getResourceAsStream("/invoke-rpc/json/rpc-output.json");
+ final NormalizedNodeContext returnValue = this.jsonBodyReader.readFrom(null,
+ null, null, this.mediaType, null, inputStream);
+ final OutputStream output = new ByteArrayOutputStream();
+ this.jsonBodyWriter.writeTo(returnValue, null, null, null, this.mediaType, null,
+ output);
+ assertTrue(output.toString().contains("lf-test"));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReader.java
new file mode 100644
index 0000000..f2a6c41
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReader.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.netconf.sal.rest.impl.JsonToPatchBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class TestJsonPatchBodyReader extends AbstractBodyReaderTest {
+ private static EffectiveModelContext schemaContext;
+
+ private final JsonToPatchBodyReader jsonToPatchBodyReader;
+
+ public TestJsonPatchBodyReader() {
+ super(schemaContext, null);
+ jsonToPatchBodyReader = new JsonToPatchBodyReader(controllerContext);
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(APPLICATION_JSON, null);
+ }
+
+ @Test
+ public void modulePatchDataTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdata.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test of successful Patch consisting of create and delete Patch operations.
+ */
+ @Test
+ public void modulePatchCreateAndDeleteTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test trying to use Patch create operation which requires value without value. Test should fail with
+ * {@link RestconfDocumentedException} with error code 400.
+ */
+ @Test
+ public void modulePatchValueMissingNegativeTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdataValueMissing.json");
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test trying to use value with Patch delete operation which does not support value. Test should fail with
+ * {@link RestconfDocumentedException} with error code 400.
+ */
+ @Test
+ public void modulePatchValueNotSupportedNegativeTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdataValueNotSupported.json");
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
+ */
+ @Test
+ public void modulePatchCompleteTargetInURITest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdataCompleteTargetInURI.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
+ */
+ @Test
+ public void modulePatchMergeOperationOnListTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHMergeOperationOnList.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
+ */
+ @Test
+ public void modulePatchMergeOperationOnContainerTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHMergeOperationOnContainer.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test reading simple leaf value.
+ */
+ @Test
+ public void modulePatchSimpleLeafValueTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHSimpleLeafValue.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReaderMountPoint.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReaderMountPoint.java
new file mode 100644
index 0000000..4ad1a65
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReaderMountPoint.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.sal.rest.impl.JsonToPatchBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class TestJsonPatchBodyReaderMountPoint extends AbstractBodyReaderTest {
+ private final JsonToPatchBodyReader jsonToPatchBodyReader;
+ private static EffectiveModelContext schemaContext;
+ private static final String MOUNT_POINT = "instance-identifier-module:cont/yang-ext:mount";
+
+ public TestJsonPatchBodyReaderMountPoint() {
+ super(schemaContext, mock(DOMMountPoint.class));
+ jsonToPatchBodyReader = new JsonToPatchBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(APPLICATION_JSON, null);
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
+ }
+
+ @Test
+ public void modulePatchDataTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHdata.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test of successful Patch consisting of create and delete Patch operations.
+ */
+ @Test
+ public void modulePatchCreateAndDeleteTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test trying to use Patch create operation which requires value without value. Test should fail with
+ * {@link RestconfDocumentedException} with error code 400.
+ */
+ @Test
+ public void modulePatchValueMissingNegativeTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdataValueMissing.json");
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test trying to use value with Patch delete operation which does not support value. Test should fail with
+ * {@link RestconfDocumentedException} with error code 400.
+ */
+ @Test
+ public void modulePatchValueNotSupportedNegativeTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHdataValueNotSupported.json");
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
+ */
+ @Test
+ public void modulePatchCompleteTargetInURITest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHdataCompleteTargetInURI.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
+ */
+ @Test
+ public void modulePatchMergeOperationOnListTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHMergeOperationOnList.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
+ */
+ @Test
+ public void modulePatchMergeOperationOnContainerTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHMergeOperationOnContainer.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test reading simple leaf value.
+ */
+ @Test
+ public void modulePatchSimpleLeafValueTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHSimpleLeafValue.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java
new file mode 100644
index 0000000..7ff353e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.Set;
+import javax.ws.rs.core.MediaType;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestXmlBodyReader extends AbstractBodyReaderTest {
+
+ private final XmlNormalizedNodeBodyReader xmlBodyReader;
+ private static EffectiveModelContext schemaContext;
+ private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = QNameModule.create(
+ XMLNamespace.of("instance:identifier:module"), Revision.of("2014-01-17"));
+
+ public TestXmlBodyReader() {
+ super(schemaContext, null);
+ xmlBodyReader = new XmlNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ testFiles.addAll(TestRestconfUtils.loadFiles("/foo-xml-test/yang"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void putXmlTest() throws Exception {
+ runXmlTest(false, "foo:top-level-list/key-value");
+ }
+
+ @Test
+ public void postXmlTest() throws Exception {
+ runXmlTest(true, "");
+ }
+
+ private void runXmlTest(final boolean isPost, final String path) throws Exception {
+ mockBodyReader(path, xmlBodyReader, isPost);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream("/foo-xml-test/foo.xml");
+ final NormalizedNodeContext nnc = xmlBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ assertNotNull(nnc);
+
+ assertTrue(nnc.getData() instanceof MapEntryNode);
+ final MapEntryNode data = (MapEntryNode) nnc.getData();
+ assertEquals(2, data.size());
+ for (final DataContainerChild child : data.body()) {
+ switch (child.getIdentifier().getNodeType().getLocalName()) {
+ case "key-leaf":
+ assertEquals("key-value", child.body());
+ break;
+
+ case "ordinary-leaf":
+ assertEquals("leaf-value", child.body());
+ break;
+ default:
+ fail();
+ }
+ }
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName());
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmldata.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerDataPutTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1");
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName);
+ final DataSchemaNode dataSchemaNodeOnPath = ((DataNodeContainer) dataSchemaNode).getDataChildByName(cont1QName);
+ final String uri = "instance-identifier-module:cont/cont1";
+ mockBodyReader(uri, xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNodeOnPath, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1");
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName);
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerAugmentDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final Module augmentModule = schemaContext.findModules(XMLNamespace.of("augment:module")).iterator().next();
+ final QName contAugmentQName = QName.create(augmentModule.getQNameModule(), "cont-augment");
+ final AugmentationIdentifier augII = new AugmentationIdentifier(Set.of(contAugmentQName));
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName())
+ .node(augII).node(contAugmentQName);
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_augment_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerChoiceAugmentDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final Module augmentModule = schemaContext.findModules(XMLNamespace.of("augment:module")).iterator().next();
+ final QName augmentChoice1QName = QName.create(augmentModule.getQNameModule(), "augment-choice1");
+ final QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName())
+ .node(new AugmentationIdentifier(Set.of(augmentChoice1QName)))
+ .node(augmentChoice1QName)
+ // FIXME: DataSchemaTreeNode intepretation seems to have a bug
+ //.node(new AugmentationIdentifier(Set.of(augmentChoice2QName)))
+ .node(augmentChoice2QName)
+ .node(QName.create(augmentChoice1QName, "case-choice-case-container1"));
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_augment_choice_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "invoke-rpc-module:rpc-test";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream("/invoke-rpc/xml/rpc-input.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null, null, null, mediaType, null,
+ inputStream);
+ checkNormalizedNodeContextRpc(returnValue);
+ final ContainerNode contNode = (ContainerNode) returnValue.getData();
+ final Optional<DataContainerChild> contDataNodePotential = contNode.findChildByArg(new NodeIdentifier(
+ QName.create(contNode.getIdentifier().getNodeType(), "cont")));
+ assertTrue(contDataNodePotential.isPresent());
+ final ContainerNode contDataNode = (ContainerNode) contDataNodePotential.get();
+ final Optional<DataContainerChild> leafDataNode = contDataNode.findChildByArg(new NodeIdentifier(
+ QName.create(contDataNode.getIdentifier().getNodeType(), "lf")));
+ assertTrue(leafDataNode.isPresent());
+ assertTrue("lf-test".equalsIgnoreCase(leafDataNode.get().body().toString()));
+ }
+
+ private static void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
+ final NormalizedNodeContext nnContext, final YangInstanceIdentifier dataNodeIdent) {
+ assertEquals(dataSchemaNode, nnContext.getInstanceIdentifierContext().getSchemaNode());
+ assertEquals(dataNodeIdent, nnContext.getInstanceIdentifierContext().getInstanceIdentifier());
+ assertNotNull(NormalizedNodes.findNode(nnContext.getData(), dataNodeIdent));
+ }
+
+ /**
+ * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
+ * used to distinguish between them to find correct one. Check if container was found not only according to its name
+ * but also by correct namespace used in payload.
+ */
+ @Test
+ public void findFooContainerUsingNamespaceTest() throws Exception {
+ mockBodyReader("", xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlDataFindFooContainer.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+
+ // check return value
+ checkNormalizedNodeContext(returnValue);
+ // check if container was found both according to its name and namespace
+ assertEquals("Not correct container found, name was ignored",
+ "foo-bar-container", returnValue.getData().getIdentifier().getNodeType().getLocalName());
+ assertEquals("Not correct container found, namespace was ignored",
+ "foo:module", returnValue.getData().getIdentifier().getNodeType().getNamespace().toString());
+ }
+
+ /**
+ * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
+ * used to distinguish between them to find correct one. Check if container was found not only according to its name
+ * but also by correct namespace used in payload.
+ */
+ @Test
+ public void findBarContainerUsingNamespaceTest() throws Exception {
+ mockBodyReader("", xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlDataFindBarContainer.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+
+ // check return value
+ checkNormalizedNodeContext(returnValue);
+ // check if container was found both according to its name and namespace
+ assertEquals("Not correct container found, name was ignored",
+ "foo-bar-container", returnValue.getData().getIdentifier().getNodeType().getLocalName());
+ assertEquals("Not correct container found, namespace was ignored",
+ "bar:module", returnValue.getData().getIdentifier().getNodeType().getNamespace().toString());
+ }
+
+ /**
+ * Test PUT operation when message root element is not the same as the last element in request URI.
+ * PUT operation message should always start with schema node from URI otherwise exception should be
+ * thrown.
+ */
+ @Test
+ public void wrongRootElementTest() throws Exception {
+ mockBodyReader("instance-identifier-module:cont", xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/bug7933.xml");
+ try {
+ xmlBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ Assert.fail("Test should fail due to malformed PUT operation message");
+ } catch (final RestconfDocumentedException exception) {
+ final RestconfError restconfError = exception.getErrors().get(0);
+ assertEquals(ErrorType.PROTOCOL, restconfError.getErrorType());
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, restconfError.getErrorTag());
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java
new file mode 100644
index 0000000..fe257db
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestXmlBodyReaderMountPoint extends AbstractBodyReaderTest {
+ private final XmlNormalizedNodeBodyReader xmlBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = QNameModule.create(
+ XMLNamespace.of("instance:identifier:module"), Revision.of("2014-01-17"));
+
+ public TestXmlBodyReaderMountPoint() {
+ super(schemaContext, mock(DOMMountPoint.class));
+ xmlBodyReader = new XmlNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/xml/xmldata.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
+ }
+
+ @Test
+ public void moduleSubContainerDataPutTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont/cont1";
+ mockBodyReader(uri, xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue,
+ QName.create(dataSchemaNode.getQName(), "cont1"));
+ }
+
+ @Test
+ public void moduleSubContainerDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/invoke-rpc-module:rpc-test";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReaderMountPoint.class
+ .getResourceAsStream("/invoke-rpc/xml/rpc-input.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContextRpc(returnValue);
+ final ContainerNode contNode = (ContainerNode) returnValue.getData();
+ final YangInstanceIdentifier yangCont = YangInstanceIdentifier.of(
+ QName.create(contNode.getIdentifier().getNodeType(), "cont"));
+ final Optional<DataContainerChild> contDataNodePotential =
+ contNode.findChildByArg(yangCont.getLastPathArgument());
+ assertTrue(contDataNodePotential.isPresent());
+ final ContainerNode contDataNode = (ContainerNode) contDataNodePotential.get();
+ final YangInstanceIdentifier yangLeaf = YangInstanceIdentifier.of(
+ QName.create(contDataNode.getIdentifier().getNodeType(), "lf"));
+ final Optional<DataContainerChild> leafDataNode = contDataNode.findChildByArg(yangLeaf.getLastPathArgument());
+ assertTrue(leafDataNode.isPresent());
+ assertTrue("lf-test".equalsIgnoreCase(leafDataNode.get().body().toString()));
+ }
+
+ private void checkExpectValueNormalizeNodeContext(
+ final DataSchemaNode dataSchemaNode,
+ final NormalizedNodeContext nnContext) {
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, nnContext, null);
+ }
+
+ protected void checkExpectValueNormalizeNodeContext(
+ final DataSchemaNode dataSchemaNode, final NormalizedNodeContext nnContext, final QName qualifiedName) {
+ YangInstanceIdentifier dataNodeIdent = YangInstanceIdentifier.of(dataSchemaNode.getQName());
+ final DOMMountPoint mountPoint = nnContext.getInstanceIdentifierContext().getMountPoint();
+ final DataSchemaNode mountDataSchemaNode =
+ modelContext(mountPoint).getDataChildByName(dataSchemaNode.getQName());
+ assertNotNull(mountDataSchemaNode);
+ if (qualifiedName != null && dataSchemaNode instanceof DataNodeContainer) {
+ final DataSchemaNode child = ((DataNodeContainer) dataSchemaNode).getDataChildByName(qualifiedName);
+ dataNodeIdent = YangInstanceIdentifier.builder(dataNodeIdent).node(child.getQName()).build();
+ assertTrue(nnContext.getInstanceIdentifierContext().getSchemaNode().equals(child));
+ } else {
+ assertTrue(mountDataSchemaNode.equals(dataSchemaNode));
+ }
+ assertNotNull(NormalizedNodes.findNode(nnContext.getData(), dataNodeIdent));
+ }
+
+ /**
+ * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
+ * used to distinguish between them to find correct one. Check if container was found not only according to its name
+ * but also by correct namespace used in payload.
+ */
+ @Test
+ public void findFooContainerUsingNamespaceTest() throws Exception {
+ mockBodyReader("instance-identifier-module:cont/yang-ext:mount", xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlDataFindFooContainer.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+
+ // check return value
+ checkMountPointNormalizedNodeContext(returnValue);
+ // check if container was found both according to its name and namespace
+ assertEquals("Not correct container found, name was ignored",
+ "foo-bar-container", returnValue.getData().getIdentifier().getNodeType().getLocalName());
+ assertEquals("Not correct container found, namespace was ignored",
+ "foo:module", returnValue.getData().getIdentifier().getNodeType().getNamespace().toString());
+ }
+
+ /**
+ * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
+ * used to distinguish between them to find correct one. Check if container was found not only according to its name
+ * but also by correct namespace used in payload.
+ */
+ @Test
+ public void findBarContainerUsingNamespaceTest() throws Exception {
+ mockBodyReader("instance-identifier-module:cont/yang-ext:mount", xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlDataFindBarContainer.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+
+ // check return value
+ checkMountPointNormalizedNodeContext(returnValue);
+ // check if container was found both according to its name and namespace
+ assertEquals("Not correct container found, name was ignored",
+ "foo-bar-container", returnValue.getData().getIdentifier().getNodeType().getLocalName());
+ assertEquals("Not correct container found, namespace was ignored",
+ "bar:module", returnValue.getData().getIdentifier().getNodeType().getNamespace().toString());
+ }
+
+ /**
+ * Test PUT operation when message root element is not the same as the last element in request URI.
+ * PUT operation message should always start with schema node from URI otherwise exception should be
+ * thrown.
+ */
+ @Test
+ public void wrongRootElementTest() throws Exception {
+ mockBodyReader("instance-identifier-module:cont/yang-ext:mount", xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/bug7933.xml");
+ try {
+ xmlBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ Assert.fail("Test should fail due to malformed PUT operation message");
+ } catch (final RestconfDocumentedException exception) {
+ final RestconfError restconfError = exception.getErrors().get(0);
+ assertEquals(ErrorType.PROTOCOL, restconfError.getErrorType());
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, restconfError.getErrorTag());
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyWriter.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyWriter.java
new file mode 100644
index 0000000..169d806
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyWriter.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.OutputStream;
+import java.util.Collection;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestXmlBodyWriter extends AbstractBodyReaderTest {
+
+ private final NormalizedNodeXmlBodyWriter xmlBodyWriter;
+ private static EffectiveModelContext schemaContext;
+
+ public TestXmlBodyWriter() {
+ super(schemaContext, null);
+ this.xmlBodyWriter = new NormalizedNodeXmlBodyWriter();
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "invoke-rpc-module:rpc-test";
+ final String pathToInputFile = "/invoke-rpc/xml/rpc-output.xml";
+ final NormalizedNodeContext nnContext = TestRestconfUtils
+ .loadNormalizedContextFromXmlFile(pathToInputFile, uri, controllerContext);
+ final OutputStream output = new ByteArrayOutputStream();
+ this.xmlBodyWriter.writeTo(nnContext, null, null, null, this.mediaType, null, output);
+ assertTrue(output.toString().contains("lf-test"));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReader.java
new file mode 100644
index 0000000..8b37ba4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReader.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.netconf.sal.rest.impl.XmlToPatchBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class TestXmlPatchBodyReader extends AbstractBodyReaderTest {
+
+ private final XmlToPatchBodyReader xmlToPatchBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ public TestXmlPatchBodyReader() {
+ super(schemaContext, null);
+ xmlToPatchBodyReader = new XmlToPatchBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws NoSuchFieldException, SecurityException {
+ schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdata.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test trying to use Patch create operation which requires value without value. Error code 400 should be returned.
+ */
+ @Test
+ public void moduleDataValueMissingNegativeTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataValueMissing.xml");
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(1, ex.getErrors().size());
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test trying to use value with Patch delete operation which does not support value. Error code 400 should be
+ * returned.
+ */
+ @Test
+ public void moduleDataNotValueNotSupportedNegativeTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml");
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(1, ex.getErrors().size());
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test of Yang Patch with absolute target path.
+ */
+ @Test
+ public void moduleDataAbsoluteTargetPathTest() throws Exception {
+ final String uri = "";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
+ */
+ @Test
+ public void modulePatchCompleteTargetInURITest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
+ */
+ @Test
+ public void moduleDataMergeOperationOnListTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
+ */
+ @Test
+ public void moduleDataMergeOperationOnContainerTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReaderMountPoint.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReaderMountPoint.java
new file mode 100644
index 0000000..614f36e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReaderMountPoint.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.sal.rest.impl.XmlToPatchBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class TestXmlPatchBodyReaderMountPoint extends AbstractBodyReaderTest {
+
+ private final XmlToPatchBodyReader xmlToPatchBodyReader;
+ private static EffectiveModelContext schemaContext;
+ private static final String MOUNT_POINT = "instance-identifier-module:cont/yang-ext:mount";
+
+ public TestXmlPatchBodyReaderMountPoint() {
+ super(schemaContext, mock(DOMMountPoint.class));
+ xmlToPatchBodyReader = new XmlToPatchBodyReader(controllerContext);
+ }
+
+ @BeforeClass
+ public static void initialization() throws NoSuchFieldException, SecurityException {
+ schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdata.xml");
+ checkPatchContextMountPoint(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ }
+
+ /**
+ * Test trying to use Patch create operation which requires value without value. Error code 400 should be returned.
+ */
+ @Test
+ public void moduleDataValueMissingNegativeTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataValueMissing.xml");
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test trying to use value with Patch delete operation which does not support value. Error code 400 should be
+ * returned.
+ */
+ @Test
+ public void moduleDataNotValueNotSupportedNegativeTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml");
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test of Yang Patch with absolute target path.
+ */
+ @Test
+ public void moduleDataAbsoluteTargetPathTest() throws Exception {
+ final String uri = MOUNT_POINT;
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
+ */
+ @Test
+ public void modulePatchCompleteTargetInURITest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
+ */
+ @Test
+ public void moduleDataMergeOperationOnListTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml");
+ checkPatchContextMountPoint(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ }
+
+ /**
+ * Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
+ */
+ @Test
+ public void moduleDataMergeOperationOnContainerTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml");
+ checkPatchContextMountPoint(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java
new file mode 100644
index 0000000..e263873
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+
+public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader {
+
+ abstract static class LeafVerifier {
+
+ Object expectedValue;
+ JsonToken expectedToken;
+
+ LeafVerifier(final Object expectedValue, final JsonToken expectedToken) {
+ this.expectedValue = expectedValue;
+ this.expectedToken = expectedToken;
+ }
+
+ abstract Object getActualValue(JsonReader reader) throws IOException;
+
+ void verify(final JsonReader reader, final String keyName) throws IOException {
+ assertEquals("Json value for key " + keyName, this.expectedValue, getActualValue(reader));
+ }
+
+ JsonToken expectedTokenType() {
+ return this.expectedToken;
+ }
+ }
+
+ static class BooleanVerifier extends LeafVerifier {
+
+ BooleanVerifier(final boolean expected) {
+ super(expected, JsonToken.BOOLEAN);
+ }
+
+ @Override
+ Object getActualValue(final JsonReader reader) throws IOException {
+ return reader.nextBoolean();
+ }
+ }
+
+ static class NumberVerifier extends LeafVerifier {
+
+ NumberVerifier(final Number expected) {
+ super(expected, JsonToken.NUMBER);
+ }
+
+ @Override
+ Object getActualValue(final JsonReader reader) throws IOException {
+ if (this.expectedValue instanceof Double) {
+ return reader.nextDouble();
+ } else if (this.expectedValue instanceof Long) {
+ return reader.nextLong();
+ } else if (this.expectedValue instanceof Integer) {
+ return reader.nextInt();
+ }
+
+ return null;
+ }
+ }
+
+ static class StringVerifier extends LeafVerifier {
+
+ StringVerifier(final String expected) {
+ super(expected, JsonToken.STRING);
+ }
+
+ @Override
+ Object getActualValue(final JsonReader reader) throws IOException {
+ return reader.nextString();
+ }
+ }
+
+ static class EmptyVerifier extends LeafVerifier {
+
+ EmptyVerifier() {
+ super(null, null);
+ }
+
+ @Override
+ Object getActualValue(final JsonReader reader) throws IOException {
+ reader.beginArray();
+ reader.nextNull();
+ reader.endArray();
+ return null;
+ }
+
+ }
+
+ static class ComplexAnyXmlVerifier extends LeafVerifier {
+
+ ComplexAnyXmlVerifier() {
+ super(null, JsonToken.BEGIN_OBJECT);
+ }
+
+ @Override
+ void verify(final JsonReader reader, final String keyName) throws IOException {
+
+ reader.beginObject();
+ final String innerKey = reader.nextName();
+ assertEquals("Json reader child key for " + keyName, "data", innerKey);
+ assertEquals("Json token type for key " + innerKey, JsonToken.BEGIN_OBJECT, reader.peek());
+
+ reader.beginObject();
+ verifyLeaf(reader, innerKey, "leaf1", "leaf1-value");
+ verifyLeaf(reader, innerKey, "leaf2", "leaf2-value");
+
+ String nextName = reader.nextName();
+ assertEquals("Json reader child key for " + innerKey, "leaf-list", nextName);
+ reader.beginArray();
+ assertEquals("Json value for key " + nextName, "leaf-list-value1", reader.nextString());
+ assertEquals("Json value for key " + nextName, "leaf-list-value2", reader.nextString());
+ reader.endArray();
+
+ nextName = reader.nextName();
+ assertEquals("Json reader child key for " + innerKey, "list", nextName);
+ reader.beginArray();
+ verifyNestedLists(reader, 1);
+ verifyNestedLists(reader, 3);
+ reader.endArray();
+
+ reader.endObject();
+ reader.endObject();
+ }
+
+ void verifyNestedLists(final JsonReader reader, int leafNum) throws IOException {
+ reader.beginObject();
+
+ final String nextName = reader.nextName();
+ assertEquals("Json reader next name", "nested-list", nextName);
+
+ reader.beginArray();
+
+ reader.beginObject();
+ verifyLeaf(reader, "nested-list", "nested-leaf", "nested-value" + leafNum++);
+ reader.endObject();
+
+ reader.beginObject();
+ verifyLeaf(reader, "nested-list", "nested-leaf", "nested-value" + leafNum);
+ reader.endObject();
+
+ reader.endArray();
+ reader.endObject();
+ }
+
+ void verifyLeaf(final JsonReader reader, final String parent, final String name,
+ final String value) throws IOException {
+ final String nextName = reader.nextName();
+ assertEquals("Json reader child key for " + parent, name, nextName);
+ assertEquals("Json token type for key " + parent, JsonToken.STRING, reader.peek());
+ assertEquals("Json value for key " + nextName, value, reader.nextString());
+ }
+
+ @Override
+ Object getActualValue(final JsonReader reader) throws IOException {
+ return null;
+ }
+ }
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException {
+ dataLoad("/cnsn-to-json/simple-data-types");
+ }
+
+ private static void verifyJsonOutput(final String jsonOutput) {
+ final StringReader strReader = new StringReader(jsonOutput);
+ final JsonReader jReader = new JsonReader(strReader);
+
+ String exception = null;
+ try {
+ jsonReadCont(jReader);
+ } catch (final IOException e) {
+ exception = e.getMessage();
+ }
+
+ assertNull("Error during reading Json output: " + exception, exception);
+ }
+
+ private static void jsonReadCont(final JsonReader jsonReader) throws IOException {
+ jsonReader.beginObject();
+ assertNotNull("cont1 is missing.", jsonReader.hasNext());
+
+ // Cont dataFromJson = new Cont(jReader.nextName());
+ jsonReader.nextName();
+ jsonReadContElements(jsonReader);
+
+ assertFalse("cont shouldn't have other element.", jsonReader.hasNext());
+ jsonReader.endObject();
+ // return dataFromJson;
+ }
+
+ private static void jsonReadContElements(final JsonReader jsonReader) throws IOException {
+ jsonReader.beginObject();
+
+ final Map<String, LeafVerifier> expectedMap = new HashMap<>();
+ expectedMap.put("lfnint8Min", new NumberVerifier(-128));
+ expectedMap.put("lfnint8Max", new NumberVerifier(127));
+ expectedMap.put("lfnint16Min", new NumberVerifier(-32768));
+ expectedMap.put("lfnint16Max", new NumberVerifier(32767));
+ expectedMap.put("lfnint32Min", new NumberVerifier(-2147483648));
+ expectedMap.put("lfnint32Max", new NumberVerifier(2147483647L));
+ expectedMap.put("lfnint64Min", new NumberVerifier(-9223372036854775808L));
+ expectedMap.put("lfnint64Max", new NumberVerifier(9223372036854775807L));
+ expectedMap.put("lfnuint8Max", new NumberVerifier(255));
+ expectedMap.put("lfnuint16Max", new NumberVerifier(65535));
+ expectedMap.put("lfnuint32Max", new NumberVerifier(4294967295L));
+ expectedMap.put("lfstr", new StringVerifier("lfstr"));
+ expectedMap.put("lfstr1", new StringVerifier(""));
+ expectedMap.put("lfbool1", new BooleanVerifier(true));
+ expectedMap.put("lfbool2", new BooleanVerifier(false));
+ expectedMap.put("lfbool3", new BooleanVerifier(false));
+ expectedMap.put("lfdecimal1", new NumberVerifier(43.32));
+ expectedMap.put("lfdecimal2", new NumberVerifier(-0.43));
+ expectedMap.put("lfdecimal3", new NumberVerifier(43d));
+ expectedMap.put("lfdecimal4", new NumberVerifier(43E3));
+ expectedMap.put("lfdecimal6", new NumberVerifier(33.12345));
+ expectedMap.put("lfenum", new StringVerifier("enum3"));
+ expectedMap.put("lfbits", new StringVerifier("bit3 bit2"));
+ expectedMap.put("lfbinary", new StringVerifier("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
+ expectedMap.put("lfunion1", new StringVerifier("324"));
+ expectedMap.put("lfunion2", new StringVerifier("33.3"));
+ expectedMap.put("lfunion3", new StringVerifier("55"));
+ expectedMap.put("lfunion4", new StringVerifier("true"));
+ expectedMap.put("lfunion5", new StringVerifier("true"));
+ expectedMap.put("lfunion6", new StringVerifier("10"));
+ expectedMap.put("lfunion7", new StringVerifier(""));
+ expectedMap.put("lfunion8", new StringVerifier(""));
+ expectedMap.put("lfunion9", new StringVerifier(""));
+ expectedMap.put("lfunion10", new StringVerifier("bt1"));
+ expectedMap.put("lfunion11", new StringVerifier("33"));
+ expectedMap.put("lfunion12", new StringVerifier("false"));
+ expectedMap.put("lfunion13", new StringVerifier("b1"));
+ expectedMap.put("lfunion14", new StringVerifier("zero"));
+ expectedMap.put("lfempty", new EmptyVerifier());
+ expectedMap.put("identityref1", new StringVerifier("simple-data-types:iden"));
+ expectedMap.put("complex-any", new ComplexAnyXmlVerifier());
+ expectedMap.put("simple-any", new StringVerifier("simple"));
+ expectedMap.put("empty-any", new StringVerifier(""));
+
+ while (jsonReader.hasNext()) {
+ final String keyName = jsonReader.nextName();
+ final JsonToken peek = jsonReader.peek();
+
+ final LeafVerifier verifier = expectedMap.remove(keyName);
+ assertNotNull("Found unexpected leaf: " + keyName, verifier);
+
+ final JsonToken expToken = verifier.expectedTokenType();
+ if (expToken != null) {
+ assertEquals("Json token type for key " + keyName, expToken, peek);
+ }
+
+ verifier.verify(jsonReader, keyName);
+ }
+
+ if (!expectedMap.isEmpty()) {
+ fail("Missing leaf nodes in Json output: " + expectedMap.keySet());
+ }
+
+ jsonReader.endObject();
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIdentityrefTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIdentityrefTest.java
new file mode 100644
index 0000000..bf262d7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIdentityrefTest.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class CnSnToJsonIdentityrefTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialization() throws FileNotFoundException, ReactorException {
+ dataLoad("/cnsn-to-json/identityref", 2, "identityref-module", "cont");
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithDataFromSeveralModulesTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithDataFromSeveralModulesTest.java
new file mode 100644
index 0000000..1b44d75
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithDataFromSeveralModulesTest.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class CnSnToJsonWithDataFromSeveralModulesTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ dataLoad("/xml-to-cnsn/data-of-several-modules/yang", 2, "module1", "cont_m1");
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java
new file mode 100644
index 0000000..71406ca
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.input.to.cnsn.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.util.concurrent.FluentFuture;
+import java.io.FileNotFoundException;
+import java.util.List;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataValidationException;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+public class RestPutListDataTest {
+ private static EffectiveModelContext schemaContextTestModule;
+
+ private static BrokerFacade brokerFacade;
+ private static RestconfImpl restconfImpl;
+
+ private static final String TEST_MODULE_NS_STRING = "test:module";
+ private static final String TEST_MODULE_REVISION = "2014-01-09";
+
+ @BeforeClass
+ public static void staticSetup() throws FileNotFoundException {
+ schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module");
+ }
+
+ @Before
+ public void initialize() throws FileNotFoundException {
+ final ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContextTestModule);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+ final PutResult result = mock(PutResult.class);
+ when(brokerFacade.commitConfigurationDataPut(any(EffectiveModelContext.class),
+ any(YangInstanceIdentifier.class), any(NormalizedNode.class), Mockito.anyString(), Mockito.anyString()))
+ .thenReturn(result);
+ when(result.getFutureOfPutData()).thenReturn(mock(FluentFuture.class));
+ when(result.getStatus()).thenReturn(Status.OK);
+ }
+
+ /**
+ * Tests whether no exception is raised if number and values of keys in URI
+ * and payload are equal.
+ */
+ @Test
+ @Ignore
+ public void testValidKeys() {
+ putListDataTest("key1value", "15", "key1value", (short) 15);
+ }
+
+ /**
+ * Tests whether an exception is raised if key values in URI and payload are
+ * different.
+ *
+ * <p>
+ * The exception should be raised from validation method
+ * {@code RestconfImpl#validateListEqualityOfListInDataAndUri}
+ */
+ @Test
+ @Ignore // RestconfDocumentedExceptionMapper needs update
+ public void testUriAndPayloadKeysDifferent() {
+ try {
+ putListDataTest("key1value", "15", "key1value", (short) 16);
+ fail("RestconfDocumentedException expected");
+ } catch (final RestconfDocumentedException e) {
+ verifyException(e, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ try {
+ putListDataTest("key1value", "15", "key1value1", (short) 16);
+ fail("RestconfDocumentedException expected");
+ } catch (final RestconfDocumentedException e) {
+ verifyException(e, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+ }
+
+ /**
+ * Tests whether an exception is raised if URI contains less key values then
+ * payload.
+ *
+ * <p>
+ * The exception is raised during {@code InstanceIdentifier} instance is
+ * built from URI
+ */
+ @Test
+ @Ignore
+ public void testMissingKeysInUri() {
+ try {
+ putListDataTest("key1value", null, "key1value", (short) 15);
+ fail("RestconfDocumentedException expected");
+ } catch (final RestconfDocumentedException e) {
+ verifyException(e, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+ }
+ }
+
+ /**
+ * Tests whether an exception is raised if URI contains more key values then
+ * payload.
+ *
+ * <p>
+ * The exception should be raised from validation method
+ * {@code RestconfImpl#validateListEqualityOfListInDataAndUri}
+ */
+ @Test
+ public void testMissingKeysInPayload() {
+ try {
+ putListDataTest("key1value", "15", "key1value", null);
+ fail("RestconfDocumentedException expected");
+ } catch (final DataValidationException e) {
+ // FIXME: thing about different approach for testing the Exception states
+ // RestconfDocumentedException is not rise in new API because you get
+ // DataValidationException from putListDataTest before you call the real rest service
+// verifyException(e, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+ }
+ }
+
+ private static void verifyException(final RestconfDocumentedException restDocumentedException,
+ final ErrorType errorType, final ErrorTag errorTag) {
+ final List<RestconfError> errors = restDocumentedException.getErrors();
+ assertEquals("getErrors() size", 1, errors.size());
+ assertEquals("RestconfError getErrorType()", errorType, errors.get(0).getErrorType());
+ assertEquals("RestconfError getErrorTag()", errorTag, errors.get(0).getErrorTag());
+ }
+
+ public void putListDataTest(final String uriKey1, final String uriKey2, final String payloadKey1,
+ final Short payloadKey2) {
+ final QName lstWithCompositeKey =
+ QName.create(TEST_MODULE_NS_STRING, TEST_MODULE_REVISION, "lst-with-composite-key");
+ final QName key1 = QName.create(TEST_MODULE_NS_STRING, TEST_MODULE_REVISION, "key1");
+ final QName key2 = QName.create(TEST_MODULE_NS_STRING, TEST_MODULE_REVISION, "key2");
+
+ final DataSchemaNode testNodeSchemaNode = schemaContextTestModule.getDataChildByName(lstWithCompositeKey);
+ assertTrue(testNodeSchemaNode != null);
+ assertTrue(testNodeSchemaNode instanceof ListSchemaNode);
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> testNodeContainer =
+ SchemaAwareBuilders.mapEntryBuilder((ListSchemaNode) testNodeSchemaNode);
+
+ var testChildren = ControllerContext.findInstanceDataChildrenByName(
+ (ListSchemaNode) testNodeSchemaNode, key1.getLocalName());
+ assertTrue(testChildren != null);
+ final DataSchemaNode testLeafKey1SchemaNode = testChildren.get(0).child;
+ assertTrue(testLeafKey1SchemaNode != null);
+ assertTrue(testLeafKey1SchemaNode instanceof LeafSchemaNode);
+ final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> leafKey1 =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) testLeafKey1SchemaNode);
+ leafKey1.withValue(payloadKey1);
+ testNodeContainer.withChild(leafKey1.build());
+
+ if (payloadKey2 != null) {
+ testChildren = ControllerContext.findInstanceDataChildrenByName(
+ (ListSchemaNode) testNodeSchemaNode, key2.getLocalName());
+ assertTrue(testChildren != null);
+ final DataSchemaNode testLeafKey2SchemaNode = testChildren.get(0).child;
+ assertNotNull(testLeafKey2SchemaNode);
+ assertTrue(testLeafKey2SchemaNode instanceof LeafSchemaNode);
+ final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> leafKey2 =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) testLeafKey2SchemaNode);
+ leafKey2.withValue(payloadKey2);
+ testNodeContainer.withChild(leafKey2.build());
+ }
+
+ final NormalizedNodeContext testCompositeContext = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(
+ SchemaInferenceStack.ofDataTreePath(schemaContextTestModule, lstWithCompositeKey)),
+ testNodeContainer.build());
+
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ restconfImpl.updateConfigurationData(toUri(uriKey1, uriKey2), testCompositeContext, uriInfo);
+ }
+
+ public void putListDataWithWrapperTest(final String uriKey1, final String uriKey2, final String payloadKey1,
+ final Short payloadKey2) {
+ putListDataTest(uriKey1, uriKey2, payloadKey1, payloadKey2);
+ }
+
+ private static String toUri(final String uriKey1, final String uriKey2) {
+ final StringBuilder uriBuilder = new StringBuilder("/test-module:lst-with-composite-key/");
+ uriBuilder.append(uriKey1);
+ if (uriKey2 != null) {
+ uriBuilder.append("/");
+ uriBuilder.append(uriKey2);
+ }
+ return uriBuilder.toString();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonIdentityrefToNnTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonIdentityrefToNnTest.java
new file mode 100644
index 0000000..f331c47
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonIdentityrefToNnTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.json.to.nn.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class JsonIdentityrefToNnTest extends AbstractBodyReaderTest {
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ public JsonIdentityrefToNnTest() {
+ super(schemaContext, null);
+ this.jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @BeforeClass
+ public static void initialize() {
+ schemaContext = schemaContextLoader("/json-to-nn/identityref", schemaContext);
+ }
+
+ @Test
+ public void jsonIdentityrefToNn() throws Exception {
+
+ final String uri = "identityref-module:cont";
+ mockBodyReader(uri, this.jsonBodyReader, false);
+ final InputStream inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/identityref/json/data.json");
+
+ final NormalizedNodeContext normalizedNodeContext = this.jsonBodyReader.readFrom(
+ null, null, null, this.mediaType, null, inputStream);
+
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+
+ assertTrue(dataTree.contains("cont1"));
+ assertTrue(dataTree
+ .contains("lf11 (identity:module?revision=2013-12-02)iden"));
+ assertTrue(dataTree
+ .contains("lf12 (identityref:module?revision=2013-12-02)iden_local"));
+ assertTrue(dataTree
+ .contains("lf13 (identityref:module?revision=2013-12-02)iden_local"));
+ assertTrue(dataTree
+ .contains("lf14 (identity:module?revision=2013-12-02)iden"));
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonLeafrefToNnTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonLeafrefToNnTest.java
new file mode 100644
index 0000000..19bba7b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonLeafrefToNnTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.json.to.nn.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class JsonLeafrefToNnTest extends AbstractBodyReaderTest {
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ public JsonLeafrefToNnTest() {
+ super(schemaContext, null);
+ this.jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @BeforeClass
+ public static void initialize() {
+ schemaContext = schemaContextLoader("/json-to-nn/leafref", schemaContext);
+ }
+
+ @Test
+ public void jsonIdentityrefToNormalizeNode() throws Exception {
+
+ final String uri = "leafref-module:cont";
+ mockBodyReader(uri, this.jsonBodyReader, false);
+ final InputStream inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/leafref/json/data.json");
+
+ final NormalizedNodeContext normalizedNodeContext = this.jsonBodyReader.readFrom(
+ null, null, null, this.mediaType, null, inputStream);
+
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("lf2 121"));
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonToNnTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonToNnTest.java
new file mode 100644
index 0000000..51d1e64
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonToNnTest.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.json.to.nn.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.Collection;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JsonToNnTest extends AbstractBodyReaderTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractBodyReaderTest.class);
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ public JsonToNnTest() {
+ super(schemaContext, null);
+ this.jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/json-to-nn/simple-list-yang/1");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/json-to-nn/simple-list-yang/3"));
+ testFiles.addAll(TestRestconfUtils.loadFiles("/json-to-nn/simple-list-yang/4"));
+ testFiles.addAll(TestRestconfUtils.loadFiles("/json-to-nn/simple-container-yang"));
+ testFiles.addAll(TestRestconfUtils.loadFiles("/common/augment/yang"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void simpleListTest() throws Exception {
+ simpleTest("/json-to-nn/simple-list.json",
+ "lst", "simple-list-yang1");
+ }
+
+ @Test
+ public void simpleContainerTest() throws Exception {
+ simpleTest("/json-to-nn/simple-container.json",
+ "cont", "simple-container-yang");
+ }
+
+ @Test
+ public void multipleItemsInLeafListTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ "/json-to-nn/multiple-leaflist-items.json",
+ "simple-list-yang1:lst");
+ assertNotNull(normalizedNodeContext);
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext
+ .getData());
+ assertTrue(dataTree.contains("45"));
+ assertTrue(dataTree.contains("55"));
+ assertTrue(dataTree.contains("66"));
+ }
+
+ @Test
+ public void multipleItemsInListTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ "/json-to-nn/multiple-items-in-list.json",
+ "multiple-items-yang:lst");
+ assertNotNull(normalizedNodeContext);
+
+ assertEquals("lst", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ verityMultipleItemsInList(normalizedNodeContext);
+ }
+
+ @Test
+ public void nullArrayToSimpleNodeWithNullValueTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ "/json-to-nn/array-with-null.json", "array-with-null-yang:cont");
+ assertNotNull(normalizedNodeContext);
+
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("lf"));
+ assertTrue(dataTree.contains("empty"));
+ }
+
+ @Test
+ public void incorrectTopLevelElementsTest() throws Exception {
+ mockBodyReader("simple-list-yang1:lst", this.jsonBodyReader, false);
+
+ InputStream inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/wrong-top-level1.json");
+
+ int countExceptions = 0;
+ RestconfDocumentedException exception = null;
+
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null,
+ inputStream);
+ } catch (final RestconfDocumentedException e) {
+ exception = e;
+ countExceptions++;
+ }
+ assertNotNull(exception);
+ assertEquals(
+ "Error parsing input: Schema node with name wrong was not found under "
+ + "(urn:ietf:params:xml:ns:netconf:base:1.0)data.",
+ exception.getErrors().get(0).getErrorMessage());
+
+ inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/wrong-top-level2.json");
+ exception = null;
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null,
+ inputStream);
+ } catch (final RestconfDocumentedException e) {
+ exception = e;
+ countExceptions++;
+ }
+ assertNotNull(exception);
+ assertEquals(
+ "Error parsing input: Schema node with name lst1 was not found under "
+ + "(urn:ietf:params:xml:ns:netconf:base:1.0)data.",
+ exception.getErrors().get(0).getErrorMessage());
+
+ inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/wrong-top-level3.json");
+ exception = null;
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null,
+ inputStream);
+ } catch (final RestconfDocumentedException e) {
+ exception = e;
+ countExceptions++;
+ }
+ assertNotNull(exception);
+ assertEquals(
+ "Error parsing input: Schema node with name lf was not found under "
+ + "(urn:ietf:params:xml:ns:netconf:base:1.0)data.",
+ exception.getErrors().get(0).getErrorMessage());
+ assertEquals(3, countExceptions);
+ }
+
+ @Test
+ public void emptyDataReadTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ "/json-to-nn/empty-data.json", "array-with-null-yang:cont");
+ assertNotNull(normalizedNodeContext);
+
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+
+ assertTrue(dataTree.contains("lflst1"));
+
+ assertTrue(dataTree.contains("lflst2 45"));
+
+ RestconfDocumentedException exception = null;
+ mockBodyReader("array-with-null-yang:cont", this.jsonBodyReader, false);
+ final InputStream inputStream = this.getClass().getResourceAsStream("/json-to-nn/empty-data.json1");
+
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null,inputStream);
+ } catch (final RestconfDocumentedException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertEquals("Error parsing input: null", exception.getErrors().get(0).getErrorMessage());
+ }
+
+ @Test
+ public void testJsonBlankInput() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC("", "array-with-null-yang:cont");
+ assertNull(normalizedNodeContext);
+ }
+
+ @Test
+ public void notSupplyNamespaceIfAlreadySupplied()throws Exception {
+ final String uri = "simple-list-yang1" + ":" + "lst";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC("/json-to-nn/simple-list.json", uri);
+ assertNotNull(normalizedNodeContext);
+
+ verifyNormaluizedNodeContext(normalizedNodeContext, "lst");
+
+ mockBodyReader("simple-list-yang2:lst", this.jsonBodyReader, false);
+ final InputStream inputStream = this.getClass().getResourceAsStream("/json-to-nn/simple-list.json");
+
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
+ fail("NormalizedNodeContext should not be create because of different namespace");
+ } catch (final RestconfDocumentedException e) {
+ LOG.warn("Read from InputStream failed. Message: {}. Status: {}", e.getMessage(), e.getStatus());
+ }
+
+ verifyNormaluizedNodeContext(normalizedNodeContext, "lst");
+ }
+
+ @Test
+ public void dataAugmentedTest() throws Exception {
+ NormalizedNodeContext normalizedNodeContext = prepareNNC("/common/augment/json/dataa.json", "main:cont");
+
+ assertNotNull(normalizedNodeContext);
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext
+ .getData());
+ assertTrue(dataTree.contains("cont1"));
+ assertTrue(dataTree.contains("lf11 lf11 value from a"));
+
+ normalizedNodeContext = prepareNNC("/common/augment/json/datab.json", "main:cont");
+
+ assertNotNull(normalizedNodeContext);
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+ dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("cont1"));
+ assertTrue(dataTree.contains("lf11 lf11 value from b"));
+ }
+
+ private void simpleTest(final String jsonPath, final String topLevelElementName,
+ final String moduleName) throws Exception {
+ final String uri = moduleName + ":" + topLevelElementName;
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(jsonPath, uri);
+ assertNotNull(normalizedNodeContext);
+
+ verifyNormaluizedNodeContext(normalizedNodeContext, topLevelElementName);
+ }
+
+ private NormalizedNodeContext prepareNNC(final String jsonPath, final String uri) throws Exception {
+ try {
+ mockBodyReader(uri, this.jsonBodyReader, false);
+ } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ LOG.warn("Operation failed due to: {}", e.getMessage());
+ }
+ final InputStream inputStream = this.getClass().getResourceAsStream(jsonPath);
+
+ NormalizedNodeContext normalizedNodeContext = null;
+
+ try {
+ normalizedNodeContext = this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
+ } catch (WebApplicationException e) {
+ // TODO Auto-generated catch block
+ }
+
+ return normalizedNodeContext;
+ }
+
+ private static void verifyNormaluizedNodeContext(final NormalizedNodeContext normalizedNodeContext,
+ final String topLevelElementName) {
+ assertEquals(topLevelElementName, normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("cont1"));
+ assertTrue(dataTree.contains("lst1"));
+ assertTrue(dataTree.contains("lflst1"));
+ assertTrue(dataTree.contains("lflst1_1"));
+ assertTrue(dataTree.contains("lflst1_2"));
+ assertTrue(dataTree.contains("lf1"));
+ }
+
+ private static void verityMultipleItemsInList(final NormalizedNodeContext normalizedNodeContext) {
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("lf11"));
+ assertTrue(dataTree.contains("lf11_1"));
+ assertTrue(dataTree.contains("lflst11"));
+ assertTrue(dataTree.contains("45"));
+ assertTrue(dataTree.contains("cont11"));
+ assertTrue(dataTree.contains("lst11"));
+ }
+
+ @Test
+ public void unsupportedDataFormatTest() throws Exception {
+ mockBodyReader("simple-list-yang1:lst", this.jsonBodyReader, false);
+
+ final InputStream inputStream = this.getClass().getResourceAsStream("/json-to-nn/unsupported-json-format.json");
+
+ RestconfDocumentedException exception = null;
+
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
+ } catch (final RestconfDocumentedException e) {
+ exception = e;
+ }
+ LOG.info(exception.getErrors().get(0).getErrorMessage());
+
+ assertTrue(exception.getErrors().get(0).getErrorMessage().contains("is not a simple type"));
+ }
+
+ @Test
+ public void invalidUriCharacterInValue() throws Exception {
+ mockBodyReader("array-with-null-yang:cont", this.jsonBodyReader, false);
+
+ final InputStream inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/invalid-uri-character-in-value.json");
+
+ final NormalizedNodeContext normalizedNodeContext = this.jsonBodyReader.readFrom(
+ null, null, null, this.mediaType, null, inputStream);
+ assertNotNull(normalizedNodeContext);
+
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("lf1 module<Name:value lf1"));
+ assertTrue(dataTree.contains("lf2 module>Name:value lf2"));
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnJsonChoiceCaseTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnJsonChoiceCaseTest.java
new file mode 100644
index 0000000..8fd5db8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnJsonChoiceCaseTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.json.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class NnJsonChoiceCaseTest extends AbstractBodyReaderTest {
+
+ private static EffectiveModelContext schemaContext;
+ private final NormalizedNodeJsonBodyWriter jsonBodyWriter;
+
+ public NnJsonChoiceCaseTest() {
+ super(schemaContext, null);
+ jsonBodyWriter = new NormalizedNodeJsonBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/nn-to-json/choice", schemaContext);
+ }
+
+ /**
+ * Test when some data are in one case node and other in another. This isn't
+ * correct. Next Json validator should return error because nodes has to be
+ * from one case below concrete choice.
+ */
+ @Test(expected = NullPointerException.class)
+ public void nodeSchemasOnVariousChoiceCasePathTest() throws Exception {
+ getJson("/nn-to-json/choice/xml/data_various_path_err.xml");
+ }
+
+ /**
+ * Test when some data are in one case node and other in another.
+ * Additionally data are loadef from various choices. This isn't correct.
+ * Next Json validator should return error because nodes has to be from one
+ * case below concrete choice.
+ */
+ @Test(expected = NullPointerException.class)
+ public void nodeSchemasOnVariousChoiceCasePathAndMultipleChoicesTest()
+ throws Exception {
+ getJson("/nn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml");
+ }
+
+ /**
+ * Test when second level data are red first, then first and at the end
+ * third level. Level represents pass through couple choice-case
+ */
+
+ @Test
+ public void nodeSchemasWithRandomOrderAccordingLevel() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_random_level.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lf1\":\"lf1 val\""));
+ assertTrue(json.contains("\"lf1aaa\":\"lf1aaa val\""));
+ assertTrue(json.contains("\"lf1aa\":\"lf1aa val\""));
+ assertTrue(json.contains("\"lf1a\":121"));
+ }
+
+ /**
+ * Test when element from no first case is used.
+ */
+ @Test
+ public void nodeSchemasNotInFirstCase() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_no_first_case.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lf1\":\"lf1 val\""));
+ assertTrue(json.contains("\"lf1ab\":\"lf1ab val\""));
+ assertTrue(json.contains("\"lf1a\":121"));
+ }
+
+ /**
+ * Test when element in case is list.
+ */
+ @Test
+ public void nodeSchemaAsList() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_list.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lst1b\":["));
+ assertTrue(json.contains("{\"lf11b\":\"lf11b_1 val\"}"));
+ assertTrue(json.contains("{\"lf11b\":\"lf11b_2 val\"}"));
+ }
+
+ /**
+ * Test when element in case is container.
+ */
+ @Test
+ public void nodeSchemaAsContainer() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_container.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"cont1c\":{"));
+ assertTrue(json.contains("\"lf11c\":\"lf11c val\""));
+ }
+
+ /**
+ * Test when element in case is leaflist.
+ */
+ @Test
+ public void nodeSchemaAsLeafList() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_leaflist.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lflst1d\":["));
+ assertTrue(json.contains("\"lflst1d_1 val\""));
+ assertTrue(json.contains("\"lflst1d_2 val\""));
+ }
+
+ @Test
+ public void nodeSchemasInMultipleChoicesTest() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_more_choices_same_level.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lf2b\":\"lf2b value\""));
+ assertTrue(json.contains("\"cont1c\":{"));
+ assertTrue(json.contains("\"lf11c\":\"lf11c val\""));
+ }
+
+ /**
+ * Test whether is possible to find data schema for node which is specified
+ * as dirrect subnode of choice (case without CASE key word).
+ */
+ @Test
+ public void nodeSchemasInCaseNotDefinedWithCaseKeyword() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_case_defined_without_case.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lf2b\":\"lf2b val\""));
+ assertTrue(json.contains("\"e1\":45"));
+ }
+
+ /**
+ * Test of multiple use of choices.
+ */
+ @Test
+ public void nodeSchemasInThreeChoicesAtSameLevel() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_three_choices_same_level.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("lf2b\":\"lf2b value"));
+ assertTrue(json.contains("lst4a\":[{"));
+ assertTrue(json.contains("{\"lf4ab\":33}"));
+ assertTrue(json.contains("{\"lf4ab\":37}"));
+ assertTrue(json.contains("\"lf1aaa\":\"lf1aaa value\""));
+ }
+
+ private String getJson(final String xmlPath) throws Exception {
+ final String uri = "choice-case-test:cont";
+ final NormalizedNodeContext testNN = TestRestconfUtils
+ .loadNormalizedContextFromXmlFile(xmlPath, uri, controllerContext);
+
+ final OutputStream output = new ByteArrayOutputStream();
+ jsonBodyWriter.writeTo(testNN, null, null, null, mediaType, null,
+ output);
+
+ return output.toString();
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonLeafrefType.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonLeafrefType.java
new file mode 100644
index 0000000..4ea6130
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonLeafrefType.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.json.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class NnToJsonLeafrefType extends AbstractBodyReaderTest {
+
+ private static EffectiveModelContext schemaContext;
+ private final NormalizedNodeJsonBodyWriter jsonBodyWriter;
+
+ public NnToJsonLeafrefType() {
+ super(schemaContext, null);
+ jsonBodyWriter = new NormalizedNodeJsonBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/nn-to-json/leafref", schemaContext);
+ }
+
+ @Test
+ public void leafrefAbsolutePathToExistingLeafTest() throws Exception {
+ final String json = toJson("/nn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml");
+ validateJson(".*\"lf3\":\\p{Blank}*\"true\".*", json);
+ }
+
+ @Test
+ public void leafrefRelativePathToExistingLeafTest() throws Exception {
+ final String json = toJson("/nn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml");
+ validateJson(".*\"lf2\":\\p{Blank}*\"121\".*", json);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void leafrefToNonExistingLeafTest() throws Exception {
+ toJson("/nn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml");
+ }
+
+ @Test
+ public void leafrefToNotLeafTest() throws Exception {
+ final String json = toJson("/nn-to-json/leafref/xml/data_ref_to_not_leaf.xml");
+ validateJson(
+ ".*\"cont-augment-module\\p{Blank}*:\\p{Blank}*lf6\":\\p{Blank}*\"44\".*",
+ json);
+ }
+
+ @Test
+ public void leafrefFromLeafListToLeafTest() throws Exception {
+ final String json = toJson("/nn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml");
+ validateJson(".*\"cont-augment-module\\p{Blank}*:\\p{Blank}*lflst1\":\\p{Blank}*.*\"34[5|6|7]\",*\"34[5|6|7]\","
+ + "*\"34[5|6|7]\".*", json);
+ }
+
+ @Test
+ public void leafrefFromLeafrefToLeafrefTest() throws Exception {
+ final String json = toJson("/nn-to-json/leafref/xml/data_from_leafref_to_leafref.xml");
+ validateJson(
+ ".*\"cont-augment-module\\p{Blank}*:\\p{Blank}*lf7\":\\p{Blank}*\"200\".*",
+ json);
+ }
+
+ private static void validateJson(final String regex, final String value) {
+ assertNotNull(value);
+ final Pattern ptrn = Pattern.compile(regex, Pattern.DOTALL);
+ final Matcher mtch = ptrn.matcher(value);
+ assertTrue(mtch.matches());
+ }
+
+ private String toJson(final String xmlDataPath) throws Exception {
+ final String uri = "main-module:cont";
+ final String pathToInputFile = xmlDataPath;
+
+ final NormalizedNodeContext testNN = TestRestconfUtils
+ .loadNormalizedContextFromXmlFile(pathToInputFile, uri, controllerContext);
+
+ final OutputStream output = new ByteArrayOutputStream();
+ jsonBodyWriter.writeTo(testNN, null, null, null, mediaType, null,
+ output);
+ final String jsonOutput = output.toString();
+
+ return jsonOutput;
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonWithAugmentTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonWithAugmentTest.java
new file mode 100644
index 0000000..d97b246
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonWithAugmentTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.json.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+@Deprecated
+public class NnToJsonWithAugmentTest extends AbstractBodyReaderTest {
+
+ private static EffectiveModelContext schemaContext;
+ private final NormalizedNodeJsonBodyWriter xmlBodyWriter;
+
+ public NnToJsonWithAugmentTest() {
+ super(schemaContext, null);
+ xmlBodyWriter = new NormalizedNodeJsonBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialize() {
+ schemaContext = schemaContextLoader("/nn-to-json/augmentation", schemaContext);
+ }
+
+ @Test
+ public void augmentedElementsToJson() throws WebApplicationException,
+ IOException {
+ final String uri = "yang:cont";
+ final String pathToInputFile = "/nn-to-json/augmentation/xml/data.xml";
+
+ final NormalizedNodeContext testNN = TestRestconfUtils
+ .loadNormalizedContextFromXmlFile(pathToInputFile, uri, controllerContext);
+
+ final OutputStream output = new ByteArrayOutputStream();
+ xmlBodyWriter
+ .writeTo(testNN, null, null, null, mediaType, null, output);
+ final String jsonOutput = output.toString();
+
+ assertNotNull(jsonOutput);
+ assertTrue(jsonOutput.contains("\"cont1\"" + ":" + '{'));
+ assertTrue(jsonOutput.contains("\"lf11\"" + ":" + "\"lf11\""));
+ assertTrue(jsonOutput.contains("\"lst1\"" + ":" + '['));
+ assertTrue(jsonOutput.contains("\"lf11\"" + ":" + "\"lf1_1\""));
+ assertTrue(jsonOutput.contains("\"lf11\"" + ":" + "\"lf1_2\""));
+ assertTrue(jsonOutput.contains("\"lflst1\"" + ":" + "["));
+ assertTrue(jsonOutput.contains("\"lf2\"" + ":" + "\"lf2\""));
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnInstanceIdentifierToXmlTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnInstanceIdentifierToXmlTest.java
new file mode 100644
index 0000000..2ab6476
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnInstanceIdentifierToXmlTest.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.xml.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.net.URISyntaxException;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+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;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+public class NnInstanceIdentifierToXmlTest extends AbstractBodyReaderTest {
+ private static EffectiveModelContext schemaContext;
+
+ private final NormalizedNodeXmlBodyWriter xmlBodyWriter = new NormalizedNodeXmlBodyWriter();
+
+ public NnInstanceIdentifierToXmlTest() {
+ super(schemaContext, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws URISyntaxException {
+ schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
+ }
+
+ @Test
+ public void nnAsYangInstanceIdentifierAugmentLeafList() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNCLeafList();
+
+ final OutputStream output = new ByteArrayOutputStream();
+
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null, mediaType, null, output);
+
+ assertNotNull(output);
+
+ final String outputJson = output.toString();
+
+ assertTrue(outputJson.contains("<cont xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "instance:identifier:module" + '"'));
+ assertTrue(outputJson.contains(">"));
+
+ assertTrue(outputJson.contains("<cont1>"));
+
+ assertTrue(outputJson.contains("<lf11 xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "augment:module:leaf:list" + '"'));
+ assertTrue(outputJson.contains(">"));
+ assertTrue(outputJson.contains("/instanceidentifier/"));
+ assertTrue(outputJson.contains("</lf11>"));
+
+ assertTrue(outputJson.contains("<lflst11 xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "augment:module:leaf:list" + '"'));
+ assertTrue(outputJson.contains(">"));
+ assertTrue(outputJson.contains("lflst11 value"));
+ assertTrue(outputJson.contains("</lflst11>"));
+
+ assertTrue(outputJson.contains("</cont1>"));
+ assertTrue(outputJson.contains("</cont>"));
+ }
+
+ private static NormalizedNodeContext prepareNNCLeafList() throws URISyntaxException {
+ final QName cont = QName.create("instance:identifier:module", "2014-01-17",
+ "cont");
+ final QName cont1 = QName.create("instance:identifier:module", "2014-01-17",
+ "cont1");
+ final QName lflst11 = QName.create("augment:module:leaf:list", "2014-01-17",
+ "lflst11");
+ final QName lf11 = QName.create("augment:module:leaf:list", "2014-01-17",
+ "lf11");
+
+ final DataSchemaNode schemaCont = schemaContext.getDataChildByName(cont);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataCont = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) schemaCont);
+
+ final DataSchemaNode schemaCont1 = ((ContainerSchemaNode) schemaCont).getDataChildByName(cont1);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataCont1 = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) schemaCont1);
+
+ final var instanceLfLst11 = ControllerContext.findInstanceDataChildrenByName(
+ (DataNodeContainer) schemaCont1, lflst11.getLocalName());
+
+ final DataSchemaNode lfLst11Schema = instanceLfLst11.get(0).child;
+ final ListNodeBuilder<Object, SystemLeafSetNode<Object>> lfLst11Data = SchemaAwareBuilders
+ .leafSetBuilder((LeafListSchemaNode) lfLst11Schema);
+
+ lfLst11Data.withChild(SchemaAwareBuilders.leafSetEntryBuilder((LeafListSchemaNode) lfLst11Schema)
+ .withValue("lflst11 value").build());
+ dataCont1.withChild(lfLst11Data.build());
+
+ final var instanceLf11 = ControllerContext.findInstanceDataChildrenByName(
+ (DataNodeContainer) schemaCont1, lf11.getLocalName());
+ final DataSchemaNode lf11Schema = instanceLf11.get(0).child;
+
+ dataCont1.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) lf11Schema)
+ .withValue("/instanceidentifier/").build());
+ dataCont.withChild(dataCont1.build());
+
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ dataCont.build());
+ }
+
+ @Test
+ public void nnAsYangInstanceIdentifierAugment() throws Exception {
+
+ final NormalizedNodeContext normalizedNodeContext = preparNNC();
+ final OutputStream output = new ByteArrayOutputStream();
+
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null,
+ mediaType, null, output);
+
+ assertNotNull(output);
+
+ final String outputJson = output.toString();
+
+ assertTrue(outputJson.contains("<cont xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "instance:identifier:module" + '"'));
+ assertTrue(outputJson.contains(">"));
+
+ assertTrue(outputJson.contains("<cont1>"));
+
+ assertTrue(outputJson.contains("<lst11 xmlns="));
+ assertTrue(outputJson.contains('"' + "augment:module" + '"'));
+ assertTrue(outputJson.contains(">"));
+
+ assertTrue(outputJson.contains(
+ "<keyvalue111>keyvalue111</keyvalue111>"));
+ assertTrue(outputJson.contains(
+ "<keyvalue112>keyvalue112</keyvalue112>"));
+
+ assertTrue(outputJson.contains("<lf111 xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "augment:augment:module" + '"'));
+ assertTrue(outputJson.contains(">/cont/cont1/lf12</lf111>"));
+
+ assertTrue(outputJson.contains("<lf112 xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "augment:augment:module" + '"'));
+ assertTrue(outputJson.contains(">lf12 value</lf112>"));
+
+ assertTrue(outputJson.contains("</lst11></cont1></cont>"));
+ }
+
+ private static NormalizedNodeContext preparNNC() {
+ final QName cont = QName.create("instance:identifier:module", "2014-01-17",
+ "cont");
+ final QName cont1 = QName.create("instance:identifier:module", "2014-01-17",
+ "cont1");
+ final QName lst11 = QName.create("augment:module", "2014-01-17", "lst11");
+ final QName lf11 = QName.create("augment:augment:module", "2014-01-17",
+ "lf111");
+ final QName lf12 = QName.create("augment:augment:module", "2014-01-17",
+ "lf112");
+ final QName keyvalue111 = QName.create("augment:module", "2014-01-17",
+ "keyvalue111");
+ final QName keyvalue112 = QName.create("augment:module", "2014-01-17",
+ "keyvalue112");
+
+ final DataSchemaNode schemaCont = schemaContext.getDataChildByName(cont);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataCont = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) schemaCont);
+
+ final DataSchemaNode schemaCont1 = ((ContainerSchemaNode) schemaCont)
+ .getDataChildByName(cont1);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataCont1 = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) schemaCont1);
+
+ final var instanceLst11 = ControllerContext.findInstanceDataChildrenByName(
+ (DataNodeContainer) schemaCont1, lst11.getLocalName());
+ final DataSchemaNode lst11Schema = instanceLst11.get(0).child;
+
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> dataLst11 = SchemaAwareBuilders
+ .mapBuilder((ListSchemaNode) lst11Schema);
+
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> dataLst11Vaule = SchemaAwareBuilders
+ .mapEntryBuilder((ListSchemaNode) lst11Schema);
+
+ dataLst11Vaule.withChild(buildLeaf(lst11Schema, keyvalue111, dataLst11, "keyvalue111"));
+
+ dataLst11Vaule.withChild(buildLeaf(lst11Schema, keyvalue112, dataLst11, "keyvalue112"));
+
+ dataLst11Vaule.withChild(buildLeaf(lst11Schema, lf11, dataLst11, "/cont/cont1/lf12"));
+
+ dataLst11Vaule.withChild(buildLeaf(lst11Schema, lf12, dataLst11, "lf12 value"));
+
+ dataLst11.withChild(dataLst11Vaule.build());
+
+ dataCont1.withChild(dataLst11.build());
+ dataCont.withChild(dataCont1.build());
+
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ dataCont.build());
+ }
+
+ private static DataContainerChild buildLeaf(final DataSchemaNode lst11Schema, final QName qname,
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> dataLst11, final Object value) {
+
+ final var instanceLf = ControllerContext.findInstanceDataChildrenByName(
+ (DataNodeContainer) lst11Schema, qname.getLocalName());
+ final DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ return SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue(value).build();
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlTest.java
new file mode 100644
index 0000000..b1385d9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlTest.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.xml.test;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Throwables;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.ri.type.BaseTypes;
+import org.opendaylight.yangtools.yang.model.ri.type.BitsTypeBuilder;
+import org.opendaylight.yangtools.yang.model.ri.type.EnumerationTypeBuilder;
+import org.opendaylight.yangtools.yang.model.ri.type.UnionTypeBuilder;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+public class NnToXmlTest extends AbstractBodyReaderTest {
+ private static EffectiveModelContext schemaContext;
+
+ private final NormalizedNodeXmlBodyWriter xmlBodyWriter;
+
+ public NnToXmlTest() {
+ super(schemaContext, null);
+ xmlBodyWriter = new NormalizedNodeXmlBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/nn-to-xml/yang", schemaContext);
+ }
+
+ @Test
+ public void nnAsYangIdentityrefToXMLTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareIdrefData(null, true);
+ nnToXml(normalizedNodeContext, "<lf11 xmlns:x=\"referenced:module\">x:iden</lf11>");
+ }
+
+ @Test
+ public void nnAsYangIdentityrefWithQNamePrefixToXMLTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareIdrefData("prefix", true);
+ nnToXml(normalizedNodeContext, "<lf11 xmlns", "=\"referenced:module\">", ":iden</lf11>");
+ }
+
+ @Test
+ public void nnAsYangIdentityrefWithPrefixToXMLTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareIdrefData("prefix", false);
+ nnToXml(normalizedNodeContext, "<lf11>no qname value</lf11>");
+ }
+
+ @Test
+ public void nnAsYangLeafrefWithPrefixToXMLTest() throws Exception {
+ nnToXml(prepareLeafrefData(), "<lfBoolean>true</lfBoolean>", "<lfLfref>true</lfLfref>");
+ }
+
+ /**
+ * Negative test when leaf of type leafref references to not-existing leaf.
+ * {@code VerifyException} is expected.
+ */
+ @Test
+ public void nnAsYangLeafrefWithPrefixToXMLNegativeTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareLeafrefNegativeData();
+
+ final IOException ex = assertThrows(IOException.class, () -> nnToXml(normalizedNodeContext,
+ "<not-existing>value</not-existing>", "<lfLfrefNegative>value</lfLfrefnegative>"));
+ final Throwable rootCause = Throwables.getRootCause(ex);
+ assertThat(rootCause, instanceOf(IllegalArgumentException.class));
+ assertEquals("Data tree child (basic:module?revision=2013-12-02)not-existing not present in schema parent "
+ + "(basic:module?revision=2013-12-02)cont", rootCause.getMessage());
+ }
+
+ @Test
+ public void nnAsYangStringToXmlTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.stringType()).deserialize("lfStr value"), "lfStr");
+ nnToXml(normalizedNodeContext, "<lfStr>lfStr value</lfStr>");
+ }
+
+ @Test
+ public void nnAsYangInt8ToXmlTest() throws Exception {
+ final String elName = "lfInt8";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.int8Type()).deserialize("14"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">14</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangInt16ToXmlTest() throws Exception {
+ final String elName = "lfInt16";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.int16Type()).deserialize("3000"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">3000</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangInt32ToXmlTest() throws Exception {
+ final String elName = "lfInt32";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.int32Type()).deserialize("201234"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">201234</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangInt64ToXmlTest() throws Exception {
+ final String elName = "lfInt64";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.int64Type()).deserialize("5123456789"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">5123456789</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangUint8ToXmlTest() throws Exception {
+ final String elName = "lfUint8";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.uint8Type()).deserialize("200"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">200</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangUint16ToXmlTest() throws Exception {
+ final String elName = "lfUint16";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.uint16Type()).deserialize("4000"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">4000</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangUint32ToXmlTest() throws Exception {
+ final String elName = "lfUint32";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.uint32Type()).deserialize("4123456789"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">4123456789</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangUint64ToXmlTest() throws Exception {
+ final String elName = "lfUint64";
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.uint64Type()).deserialize("5123456789"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">5123456789</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangBinaryToXmlTest() throws Exception {
+ final String elName = "lfBinary";
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.binaryType())
+ .deserialize("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"),
+ elName);
+ nnToXml(normalizedNodeContext,
+ "<" + elName + ">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangBitsToXmlTest() throws Exception {
+ final BitsTypeDefinition.Bit mockBit1 = Mockito.mock(BitsTypeDefinition.Bit.class);
+ Mockito.when(mockBit1.getName()).thenReturn("one");
+ Mockito.when(mockBit1.getPosition()).thenReturn(Uint32.ONE);
+ final BitsTypeDefinition.Bit mockBit2 = Mockito.mock(BitsTypeDefinition.Bit.class);
+ Mockito.when(mockBit2.getName()).thenReturn("two");
+ Mockito.when(mockBit2.getPosition()).thenReturn(Uint32.TWO);
+ final BitsTypeBuilder bitsTypeBuilder = BaseTypes.bitsTypeBuilder(QName.create("foo", "foo"));
+ bitsTypeBuilder.addBit(mockBit1);
+ bitsTypeBuilder.addBit(mockBit2);
+
+ final String elName = "lfBits";
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(bitsTypeBuilder.build()).deserialize("one two"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">one two</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangEnumerationToXmlTest() throws Exception {
+ final EnumTypeDefinition.EnumPair mockEnum = Mockito.mock(EnumTypeDefinition.EnumPair.class);
+ Mockito.when(mockEnum.getName()).thenReturn("enum2");
+
+ final EnumerationTypeBuilder enumerationTypeBuilder = BaseTypes
+ .enumerationTypeBuilder(QName.create("foo", "foo"));
+ enumerationTypeBuilder.addEnum(mockEnum);
+
+ final String elName = "lfEnumeration";
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(enumerationTypeBuilder.build()).deserialize("enum2"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">enum2</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangEmptyToXmlTest() throws Exception {
+ final String elName = "lfEmpty";
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.emptyType()).deserialize(""), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + "/>");
+ }
+
+ @Test
+ public void nnAsYangBooleanToXmlTest() throws Exception {
+ final String elName = "lfBoolean";
+ NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.booleanType()).deserialize("false"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">false</" + elName + ">");
+
+ normalizedNodeContext = prepareNNC(TypeDefinitionAwareCodec.from(BaseTypes.booleanType()).deserialize("true"),
+ elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">true</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangUnionToXmlTest() throws Exception {
+ final BitsTypeDefinition.Bit mockBit1 = Mockito.mock(BitsTypeDefinition.Bit.class);
+ Mockito.when(mockBit1.getName()).thenReturn("first");
+ Mockito.when(mockBit1.getPosition()).thenReturn(Uint32.ONE);
+ final BitsTypeDefinition.Bit mockBit2 = Mockito.mock(BitsTypeDefinition.Bit.class);
+ Mockito.when(mockBit2.getName()).thenReturn("second");
+ Mockito.when(mockBit2.getPosition()).thenReturn(Uint32.TWO);
+
+ final BitsTypeBuilder bitsTypeBuilder = BaseTypes.bitsTypeBuilder(QName.create("foo", "foo"));
+ bitsTypeBuilder.addBit(mockBit1);
+ bitsTypeBuilder.addBit(mockBit2);
+
+ final UnionTypeBuilder unionTypeBuilder = BaseTypes.unionTypeBuilder(QName.create("foo", "foo"));
+ unionTypeBuilder.addType(BaseTypes.int8Type());
+ unionTypeBuilder.addType(bitsTypeBuilder.build());
+ unionTypeBuilder.addType(BaseTypes.booleanType());
+ unionTypeBuilder.addType(BaseTypes.stringType());
+
+ final String elName = "lfUnion";
+
+ // test int8
+ final String int8 = "15";
+ NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(unionTypeBuilder.build()).deserialize(int8), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">15</" + elName + ">");
+
+ // test bits
+ final String bits = "first second";
+ normalizedNodeContext = prepareNNC(TypeDefinitionAwareCodec.from(unionTypeBuilder.build()).deserialize(bits),
+ elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">[first, second]</" + elName + ">");
+
+ // test boolean
+ final String bool = "true";
+ normalizedNodeContext = prepareNNC(TypeDefinitionAwareCodec.from(unionTypeBuilder.build()).deserialize(bool),
+ elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">true</" + elName + ">");
+
+ // test string
+ final String s = "Hi!";
+ normalizedNodeContext = prepareNNC(TypeDefinitionAwareCodec.from(unionTypeBuilder.build()).deserialize(s),
+ elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">Hi!</" + elName + ">");
+ }
+
+ private static NormalizedNodeContext prepareNNC(final Object object, final String name) {
+ final QName cont = QName.create("basic:module", "2013-12-02", "cont");
+ final QName lf = QName.create("basic:module", "2013-12-02", name);
+
+ final DataSchemaNode contSchema = schemaContext.getDataChildByName(cont);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contData = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchema);
+
+ final var instanceLf = ControllerContext
+ .findInstanceDataChildrenByName((DataNodeContainer) contSchema, lf.getLocalName());
+ final DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ contData.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue(object).build());
+
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ contData.build());
+ }
+
+ private void nnToXml(final NormalizedNodeContext normalizedNodeContext, final String... xmlRepresentation)
+ throws Exception {
+ final OutputStream output = new ByteArrayOutputStream();
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null, mediaType, null, output);
+
+ for (String element : xmlRepresentation) {
+ assertTrue(output.toString().contains(element));
+ }
+ }
+
+ private static NormalizedNodeContext prepareLeafrefData() {
+ final QName cont = QName.create("basic:module", "2013-12-02", "cont");
+ final QName lfBoolean = QName.create("basic:module", "2013-12-02", "lfBoolean");
+ final QName lfLfref = QName.create("basic:module", "2013-12-02", "lfLfref");
+
+ final DataSchemaNode contSchema = schemaContext.getDataChildByName(cont);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contData = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchema);
+
+ var instanceLf = ControllerContext
+ .findInstanceDataChildrenByName((DataNodeContainer) contSchema, lfBoolean.getLocalName());
+ DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ contData.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue(Boolean.TRUE).build());
+
+ instanceLf = ControllerContext.findInstanceDataChildrenByName((DataNodeContainer) contSchema,
+ lfLfref.getLocalName());
+ schemaLf = instanceLf.get(0).child;
+
+ contData.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue("true").build());
+
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ contData.build());
+ }
+
+ private static NormalizedNodeContext prepareLeafrefNegativeData() {
+ final QName cont = QName.create("basic:module", "2013-12-02", "cont");
+ final QName lfLfref = QName.create("basic:module", "2013-12-02", "lfLfrefNegative");
+
+ final DataSchemaNode contSchema = schemaContext.getDataChildByName(cont);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contData = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchema);
+
+ final var instanceLf = ControllerContext.findInstanceDataChildrenByName((DataNodeContainer)
+ contSchema, lfLfref.getLocalName());
+ final DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ contData.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue("value").build());
+
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ contData.build());
+ }
+
+ private static NormalizedNodeContext prepareIdrefData(final String prefix, final boolean valueAsQName) {
+ final QName cont = QName.create("basic:module", "2013-12-02", "cont");
+ final QName cont1 = QName.create("basic:module", "2013-12-02", "cont1");
+ final QName lf11 = QName.create("basic:module", "2013-12-02", "lf11");
+
+ final DataSchemaNode contSchema = schemaContext.getDataChildByName(cont);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contData = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchema);
+
+ final DataSchemaNode cont1Schema = ((ContainerSchemaNode) contSchema).getDataChildByName(cont1);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> cont1Data = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) cont1Schema);
+
+ Object value = null;
+ if (valueAsQName) {
+ value = QName.create("referenced:module", "2013-12-02", "iden");
+ } else {
+ value = "no qname value";
+ }
+
+ final var instanceLf = ControllerContext
+ .findInstanceDataChildrenByName((DataNodeContainer) cont1Schema, lf11.getLocalName());
+ final DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ cont1Data.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue(value).build());
+
+ contData.withChild(cont1Data.build());
+
+ final NormalizedNodeContext testNormalizedNodeContext = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ contData.build());
+ return testNormalizedNodeContext;
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithChoiceTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithChoiceTest.java
new file mode 100644
index 0000000..9d2954d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithChoiceTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.xml.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+public class NnToXmlWithChoiceTest extends AbstractBodyReaderTest {
+
+ private final NormalizedNodeXmlBodyWriter xmlBodyWriter;
+ private static EffectiveModelContext schemaContext;
+
+ public NnToXmlWithChoiceTest() {
+ super(schemaContext, null);
+ xmlBodyWriter = new NormalizedNodeXmlBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/nn-to-xml/choice", schemaContext);
+ }
+
+ @Test
+ public void cnSnToXmlWithYangChoice() throws Exception {
+ NormalizedNodeContext normalizedNodeContext = prepareNNC("lf1",
+ "String data1");
+ OutputStream output = new ByteArrayOutputStream();
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null,
+ mediaType, null, output);
+ assertTrue(output.toString().contains("<lf1>String data1</lf1>"));
+
+ normalizedNodeContext = prepareNNC("lf2", "String data2");
+ output = new ByteArrayOutputStream();
+
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null,
+ mediaType, null, output);
+ assertTrue(output.toString().contains("<lf2>String data2</lf2>"));
+ }
+
+ private static NormalizedNodeContext prepareNNC(final String name, final Object value) {
+
+ final QName contQname = QName.create("module:with:choice", "2013-12-18",
+ "cont");
+ final QName lf = QName.create("module:with:choice", "2013-12-18", name);
+ final QName choA = QName.create("module:with:choice", "2013-12-18", "choA");
+
+ final DataSchemaNode contSchemaNode = schemaContext
+ .getDataChildByName(contQname);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataContainerNodeAttrBuilder = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchemaNode);
+
+ final DataSchemaNode choiceSchemaNode = ((ContainerSchemaNode) contSchemaNode)
+ .getDataChildByName(choA);
+ assertTrue(choiceSchemaNode instanceof ChoiceSchemaNode);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> dataChoice = SchemaAwareBuilders
+ .choiceBuilder((ChoiceSchemaNode) choiceSchemaNode);
+
+ final var instanceLf = ControllerContext
+ .findInstanceDataChildrenByName(
+ (DataNodeContainer) contSchemaNode, lf.getLocalName());
+ final DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ dataChoice.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf)
+ .withValue(value).build());
+
+ dataContainerNodeAttrBuilder.withChild(dataChoice.build());
+
+ final NormalizedNodeContext testNormalizedNodeContext = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, contQname)),
+ dataContainerNodeAttrBuilder.build());
+
+ return testNormalizedNodeContext;
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithDataFromSeveralModulesTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithDataFromSeveralModulesTest.java
new file mode 100644
index 0000000..a9cf7a6
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithDataFromSeveralModulesTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.xml.test;
+
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Preconditions;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URISyntaxException;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+public class NnToXmlWithDataFromSeveralModulesTest extends
+ AbstractBodyReaderTest {
+
+ private final NormalizedNodeXmlBodyWriter xmlBodyWriter;
+ private static EffectiveModelContext schemaContext;
+
+ public NnToXmlWithDataFromSeveralModulesTest() {
+ super(schemaContext, null);
+ xmlBodyWriter = new NormalizedNodeXmlBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialize() {
+ schemaContext = schemaContextLoader("/nn-to-xml/data-of-several-modules/yang", schemaContext);
+ }
+
+ @Test
+ public void dataFromSeveralModulesToXmlTest()
+ throws WebApplicationException, IOException, URISyntaxException {
+ final NormalizedNodeContext normalizedNodeContext = prepareNormalizedNodeContext();
+ final OutputStream output = new ByteArrayOutputStream();
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null,
+ mediaType, null, output);
+
+ final String outputString = output.toString();
+ // data
+ assertTrue(outputString
+ .contains(
+ "<data xmlns=" + '"'
+ + "urn:ietf:params:xml:ns:netconf:base:1.0"
+ + '"' + '>'));
+ // cont m2
+ assertTrue(outputString.contains(
+ "<cont_m2 xmlns=" + '"' + "module:two" + '"' + '>'));
+ assertTrue(outputString.contains("<lf1_m2>lf1 m2 value</lf1_m2>"));
+ assertTrue(outputString.contains("<contB_m2/>"));
+ assertTrue(outputString.contains("</cont_m2>"));
+
+ // cont m1
+ assertTrue(outputString.contains(
+ "<cont_m1 xmlns=" + '"' + "module:one" + '"' + '>'));
+ assertTrue(outputString.contains("<contB_m1/>"));
+ assertTrue(outputString.contains("<lf1_m1>lf1 m1 value</lf1_m1>"));
+ assertTrue(outputString.contains("</cont_m1>"));
+
+ // end
+ assertTrue(output.toString().contains("</data>"));
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ private static NormalizedNodeContext prepareNormalizedNodeContext() {
+ final String rev = "2014-01-17";
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataContSchemaContNode = SchemaAwareBuilders
+ .containerBuilder(schemaContext);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> modul1 = buildContBuilderMod1(
+ "module:one", rev, "cont_m1", "contB_m1", "lf1_m1",
+ "lf1 m1 value");
+ dataContSchemaContNode.withChild(modul1.build());
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> modul2 = buildContBuilderMod1(
+ "module:two", rev, "cont_m2", "contB_m2", "lf1_m2",
+ "lf1 m2 value");
+ dataContSchemaContNode.withChild(modul2.build());
+
+ final NormalizedNodeContext testNormalizedNodeContext = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofLocalRoot(schemaContext),
+ dataContSchemaContNode.build());
+
+ return testNormalizedNodeContext;
+ }
+
+ private static DataContainerNodeBuilder<NodeIdentifier, ContainerNode> buildContBuilderMod1(
+ final String uri, final String rev, final String cont, final String contB, final String lf1,
+ final String lf1Value) {
+ 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 DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataContainerNodeAttrBuilder = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchemaNode);
+
+ Preconditions.checkState(contSchemaNode instanceof ContainerSchemaNode);
+ final var instanceLf1_m1 = ControllerContext.findInstanceDataChildrenByName(
+ (DataNodeContainer) contSchemaNode, lf1Qname.getLocalName());
+ final DataSchemaNode schemaLf1_m1 = instanceLf1_m1.get(0).child;
+
+ dataContainerNodeAttrBuilder.withChild(SchemaAwareBuilders
+ .leafBuilder((LeafSchemaNode) schemaLf1_m1)
+ .withValue(lf1Value).build());
+
+ final DataSchemaNode contBSchemaNode = ((ContainerSchemaNode) contSchemaNode)
+ .getDataChildByName(contBQname);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataContainerB = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contBSchemaNode);
+
+ return dataContainerNodeAttrBuilder.withChild(dataContainerB.build());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bierman02RestConfWiringTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bierman02RestConfWiringTest.java
new file mode 100644
index 0000000..990453f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bierman02RestConfWiringTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.inject.AbstractModule;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import javax.inject.Inject;
+import org.junit.Rule;
+import org.junit.Test;
+import org.opendaylight.aaa.filterchain.configuration.CustomFilterAdapterConfiguration;
+import org.opendaylight.aaa.web.WebServer;
+import org.opendaylight.aaa.web.testutils.TestWebClient;
+import org.opendaylight.aaa.web.testutils.WebTestModule;
+import org.opendaylight.controller.sal.restconf.impl.test.incubate.InMemoryMdsalModule;
+import org.opendaylight.infrautils.inject.guice.testutils.AnnotationsModule;
+import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
+import org.opendaylight.netconf.sal.restconf.api.RestConfConfig;
+import org.opendaylight.netconf.sal.restconf.impl.Bierman02RestConfWiring;
+
+/**
+ * Tests if the {@link Bierman02RestConfWiring} works.
+ *
+ * @author Michael Vorburger.ch
+ */
+public class Bierman02RestConfWiringTest {
+
+ public static class TestModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(Bierman02RestConfWiring.class).asEagerSingleton();
+ bind(RestConfConfig.class).toInstance(() -> 9090);
+ bind(CustomFilterAdapterConfiguration.class).toInstance(listener -> { });
+ }
+ }
+
+ public @Rule GuiceRule guice = new GuiceRule(TestModule.class,
+ InMemoryMdsalModule.class, WebTestModule.class, AnnotationsModule.class);
+
+ @Inject WebServer webServer;
+ @Inject TestWebClient webClient;
+
+ @Test
+ public void testWiring() throws IOException, InterruptedException, URISyntaxException {
+ assertEquals(200, webClient.request("GET", "/restconf/modules/").statusCode());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java
new file mode 100644
index 0000000..8443712
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2014, 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateBooleanFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
+
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import java.util.Optional;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMNotificationService;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.restconf.common.ErrorTags;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.CreateDataChangeEventSubscriptionInput1.Scope;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+/**
+ * Unit tests for BrokerFacade.
+ *
+ * @author Thomas Pantelis
+ */
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class BrokerFacadeTest {
+
+ @Mock
+ private DOMDataBroker domDataBroker;
+ @Mock
+ private DOMNotificationService domNotification;
+ @Mock
+ private DOMRpcService mockRpcService;
+ @Mock
+ private DOMMountPoint mockMountInstance;
+ @Mock
+ private DOMDataTreeReadTransaction readTransaction;
+ @Mock
+ private DOMDataTreeWriteTransaction writeTransaction;
+ @Mock
+ private DOMDataTreeReadWriteTransaction rwTransaction;
+
+ private BrokerFacade brokerFacade;
+ private final NormalizedNode dummyNode = createDummyNode("test:module", "2014-01-09", "interfaces");
+ private final FluentFuture<Optional<NormalizedNode>> dummyNodeInFuture = wrapDummyNode(dummyNode);
+ private final QName qname = TestUtils.buildQName("interfaces","test:module", "2014-01-09");
+ private final YangInstanceIdentifier instanceID = YangInstanceIdentifier.builder().node(qname).build();
+ private ControllerContext controllerContext;
+
+ @Before
+ public void setUp() throws Exception {
+ controllerContext = TestRestconfUtils.newControllerContext(
+ TestUtils.loadSchemaContext("/full-versions/test-module", "/modules"));
+
+ brokerFacade = BrokerFacade.newInstance(mockRpcService, domDataBroker, domNotification, controllerContext);
+
+ when(domDataBroker.newReadOnlyTransaction()).thenReturn(readTransaction);
+ when(domDataBroker.newReadWriteTransaction()).thenReturn(rwTransaction);
+ when(domDataBroker.getExtensions()).thenReturn(ImmutableClassToInstanceMap.of(
+ DOMDataTreeChangeService.class, Mockito.mock(DOMDataTreeChangeService.class)));
+ }
+
+ private static FluentFuture<Optional<NormalizedNode>> wrapDummyNode(final NormalizedNode dummyNode) {
+ return immediateFluentFuture(Optional.of(dummyNode));
+ }
+
+ private static FluentFuture<Boolean> wrapExistence(final boolean exists) {
+ return immediateBooleanFluentFuture(exists);
+ }
+
+ /**
+ * Value of this node shouldn't be important for testing purposes.
+ */
+ private static NormalizedNode createDummyNode(final String namespace, final String date, final String localName) {
+ return Builders.containerBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create(namespace, date, localName)))
+ .build();
+ }
+
+ @Test
+ public void testReadConfigurationData() {
+ when(readTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn(
+ dummyNodeInFuture);
+
+ final NormalizedNode actualNode = brokerFacade.readConfigurationData(instanceID);
+
+ assertSame("readConfigurationData", dummyNode, actualNode);
+ }
+
+ @Test
+ public void testReadOperationalData() {
+ when(readTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn(
+ dummyNodeInFuture);
+
+ final NormalizedNode actualNode = brokerFacade.readOperationalData(instanceID);
+
+ assertSame("readOperationalData", dummyNode, actualNode);
+ }
+
+ @Test
+ public void test503() throws Exception {
+ final RpcError error = RpcResultBuilder.newError(ErrorType.TRANSPORT, ErrorTag.RESOURCE_DENIED,
+ "Master is down. Please try again.");
+ doReturn(immediateFailedFluentFuture(new ReadFailedException("Read from transaction failed", error)))
+ .when(readTransaction).read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class));
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> brokerFacade.readConfigurationData(instanceID, "explicit"));
+ final List<RestconfError> errors = ex.getErrors();
+ assertEquals(1, errors.size());
+ assertEquals("getErrorTag", ErrorTags.RESOURCE_DENIED_TRANSPORT, errors.get(0).getErrorTag());
+ assertEquals("getErrorType", ErrorType.TRANSPORT,errors.get(0).getErrorType());
+ assertEquals("getErrorMessage", "Master is down. Please try again.", errors.get(0).getErrorMessage());
+ }
+
+ @Test
+ public void testInvokeRpc() throws Exception {
+ final DOMRpcResult expResult = mock(DOMRpcResult.class);
+ doReturn(immediateFluentFuture(expResult)).when(mockRpcService).invokeRpc(qname, dummyNode);
+
+ final ListenableFuture<? extends DOMRpcResult> actualFuture = brokerFacade.invokeRpc(qname,
+ dummyNode);
+ assertNotNull("Future is null", actualFuture);
+ final DOMRpcResult actualResult = actualFuture.get();
+ assertSame("invokeRpc", expResult, actualResult);
+ }
+
+ @Test
+ public void testCommitConfigurationDataPut() throws Exception {
+ doReturn(CommitInfo.emptyFluentFuture()).when(rwTransaction).commit();
+
+ doReturn(immediateFluentFuture(Optional.of(mock(NormalizedNode.class)))).when(rwTransaction)
+ .read(LogicalDatastoreType.CONFIGURATION, instanceID);
+
+ final PutResult result = brokerFacade.commitConfigurationDataPut(mock(EffectiveModelContext.class),
+ instanceID, dummyNode, null, null);
+
+ assertSame("commitConfigurationDataPut", CommitInfo.emptyFluentFuture(), result.getFutureOfPutData());
+
+ final InOrder inOrder = inOrder(domDataBroker, rwTransaction);
+ inOrder.verify(domDataBroker).newReadWriteTransaction();
+ inOrder.verify(rwTransaction).put(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode);
+ inOrder.verify(rwTransaction).commit();
+ }
+
+ @Test
+ public void testCommitConfigurationDataPost() {
+ when(rwTransaction.exists(LogicalDatastoreType.CONFIGURATION, instanceID))
+ .thenReturn(wrapExistence(false));
+
+ doReturn(CommitInfo.emptyFluentFuture()).when(rwTransaction).commit();
+
+ final FluentFuture<? extends CommitInfo> actualFuture = brokerFacade
+ .commitConfigurationDataPost(mock(EffectiveModelContext.class), instanceID, dummyNode, null,
+ null);
+
+ assertSame("commitConfigurationDataPost", CommitInfo.emptyFluentFuture(), actualFuture);
+
+ final InOrder inOrder = inOrder(domDataBroker, rwTransaction);
+ inOrder.verify(domDataBroker).newReadWriteTransaction();
+ inOrder.verify(rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, instanceID);
+ inOrder.verify(rwTransaction).put(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode);
+ inOrder.verify(rwTransaction).commit();
+ }
+
+ @Test(expected = RestconfDocumentedException.class)
+ public void testCommitConfigurationDataPostAlreadyExists() {
+ when(rwTransaction.exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class)))
+ .thenReturn(immediateTrueFluentFuture());
+ try {
+ // Schema context is only necessary for ensuring parent structure
+ brokerFacade.commitConfigurationDataPost((EffectiveModelContext) null, instanceID, dummyNode,
+ null, null);
+ } catch (final RestconfDocumentedException e) {
+ assertEquals("getErrorTag", ErrorTag.DATA_EXISTS, e.getErrors().get(0).getErrorTag());
+ throw e;
+ }
+ }
+
+ /**
+ * Positive test of delete operation when data to delete exits. Returned value and order of steps are validated.
+ */
+ @Test
+ public void testCommitConfigurationDataDelete() throws Exception {
+ // assume that data to delete exists
+ prepareDataForDelete(true);
+
+ // expected result
+ doReturn(CommitInfo.emptyFluentFuture()).when(rwTransaction).commit();
+
+ // test
+ final FluentFuture<? extends CommitInfo> actualFuture = brokerFacade
+ .commitConfigurationDataDelete(instanceID);
+
+ // verify result and interactions
+ assertSame("commitConfigurationDataDelete", CommitInfo.emptyFluentFuture(), actualFuture);
+
+ // check exists, delete, submit
+ final InOrder inOrder = inOrder(domDataBroker, rwTransaction);
+ inOrder.verify(rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, instanceID);
+ inOrder.verify(rwTransaction).delete(LogicalDatastoreType.CONFIGURATION, instanceID);
+ inOrder.verify(rwTransaction).commit();
+ }
+
+ /**
+ * Negative test of delete operation when data to delete does not exist. Error DATA_MISSING should be returned.
+ */
+ @Test
+ public void testCommitConfigurationDataDeleteNoData() throws Exception {
+ // assume that data to delete does not exist
+ prepareDataForDelete(false);
+
+ // try to delete and expect DATA_MISSING error
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> brokerFacade.commitConfigurationDataDelete(instanceID));
+ final List<RestconfError> errors = ex.getErrors();
+ assertEquals(1, errors.size());
+ assertEquals(ErrorType.PROTOCOL, errors.get(0).getErrorType());
+ assertEquals(ErrorTag.DATA_MISSING, errors.get(0).getErrorTag());
+ }
+
+ /**
+ * Prepare conditions to test delete operation. Data to delete exists or does not exist according to value of
+ * {@code assumeDataExists} parameter.
+ * @param assumeDataExists boolean to assume if data exists
+ */
+ private void prepareDataForDelete(final boolean assumeDataExists) {
+ when(rwTransaction.exists(LogicalDatastoreType.CONFIGURATION, instanceID))
+ .thenReturn(immediateBooleanFluentFuture(assumeDataExists));
+ }
+
+ @Test
+ public void testRegisterToListenDataChanges() {
+ final ListenerAdapter listener = Notificator.createListener(instanceID, "stream",
+ NotificationOutputType.XML, controllerContext);
+
+ @SuppressWarnings("unchecked")
+ final ListenerRegistration<ListenerAdapter> mockRegistration = mock(ListenerRegistration.class);
+
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(DOMDataTreeChangeService.class);
+ DOMDataTreeIdentifier loc = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, instanceID);
+ when(changeService.registerDataTreeChangeListener(eq(loc), eq(listener))).thenReturn(mockRegistration);
+
+ brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, Scope.BASE, listener);
+
+ verify(changeService).registerDataTreeChangeListener(loc, listener);
+
+ assertEquals("isListening", true, listener.isListening());
+
+ brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, Scope.BASE, listener);
+ verifyNoMoreInteractions(changeService);
+ }
+
+ /**
+ * Create, register, close and remove notification listener.
+ */
+ @Test
+ public void testRegisterToListenNotificationChanges() throws Exception {
+ // create test notification listener
+ final String identifier = "create-notification-stream/toaster:toastDone";
+ Notificator.createNotificationListener(
+ List.of(Absolute.of(QName.create("http://netconfcentral.org/ns/toaster", "2009-11-20", "toastDone"))),
+ identifier, "XML", controllerContext);
+ final NotificationListenerAdapter listener = Notificator.getNotificationListenerFor(identifier).get(0);
+
+ // mock registration
+ final ListenerRegistration<NotificationListenerAdapter> registration = mock(ListenerRegistration.class);
+ when(domNotification.registerNotificationListener(listener, listener.getSchemaPath()))
+ .thenReturn(registration);
+
+ // test to register listener for the first time
+ brokerFacade.registerToListenNotification(listener);
+ assertEquals("Registration was not successful", true, listener.isListening());
+
+ // try to register for the second time
+ brokerFacade.registerToListenNotification(listener);
+ assertEquals("Registration was not successful", true, listener.isListening());
+
+ // registrations should be invoked only once
+ verify(domNotification, times(1)).registerNotificationListener(listener, listener.getSchemaPath());
+
+ final DOMTransactionChain transactionChain = mock(DOMTransactionChain.class);
+ final DOMDataTreeWriteTransaction wTx = mock(DOMDataTreeWriteTransaction.class);
+ // close and remove test notification listener
+ listener.close();
+ Notificator.removeListenerIfNoSubscriberExists(listener);
+ }
+
+ /**
+ * Test Patch method on the server with no data.
+ */
+ @Test
+ public void testPatchConfigurationDataWithinTransactionServer() throws Exception {
+ final PatchContext patchContext = mock(PatchContext.class);
+
+ when(patchContext.getData()).thenReturn(List.of());
+ // no mount point
+ doReturn(InstanceIdentifierContext.ofPath(SchemaInferenceStack.of(mock(EffectiveModelContext.class)),
+ mock(DataSchemaNode.class), YangInstanceIdentifier.empty(), null))
+ .when(patchContext).getInstanceIdentifierContext();
+
+ doReturn(CommitInfo.emptyFluentFuture()).when(rwTransaction).commit();
+
+ final PatchStatusContext status = brokerFacade.patchConfigurationDataWithinTransaction(patchContext);
+
+ // assert success
+ assertTrue("Patch operation should be successful on server", status.isOk());
+ }
+
+ /**
+ * Test Patch method on mounted device with no data.
+ */
+ @Test
+ public void testPatchConfigurationDataWithinTransactionMount() throws Exception {
+ final PatchContext patchContext = mock(PatchContext.class);
+ final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
+ final DOMDataBroker mountDataBroker = mock(DOMDataBroker.class);
+ final DOMDataTreeReadWriteTransaction transaction = mock(DOMDataTreeReadWriteTransaction.class);
+
+ when(patchContext.getData()).thenReturn(List.of());
+ // return mount point with broker
+ doReturn(InstanceIdentifierContext.ofPath(SchemaInferenceStack.of(mock(EffectiveModelContext.class)),
+ mock(DataSchemaNode.class), YangInstanceIdentifier.empty(), mountPoint))
+ .when(patchContext).getInstanceIdentifierContext();
+
+ when(mountPoint.getService(DOMDataBroker.class)).thenReturn(Optional.of(mountDataBroker));
+ when(mountPoint.getService(DOMSchemaService.class)).thenReturn(Optional.empty());
+ when(mountDataBroker.newReadWriteTransaction()).thenReturn(transaction);
+ doReturn(CommitInfo.emptyFluentFuture()).when(transaction).commit();
+
+ final PatchStatusContext status = brokerFacade.patchConfigurationDataWithinTransaction(patchContext);
+
+ // assert success
+ assertTrue("Patch operation should be successful on mounted device", status.isOk());
+ }
+
+ /**
+ * Negative test for Patch operation when mounted device does not support {@link DOMDataBroker service.}
+ * Patch operation should fail with global error.
+ */
+ @Test
+ public void testPatchConfigurationDataWithinTransactionMountFail() throws Exception {
+ final PatchContext patchContext = mock(PatchContext.class);
+ final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
+
+ doReturn(InstanceIdentifierContext.ofPath(SchemaInferenceStack.of(mock(EffectiveModelContext.class)),
+ mock(DataSchemaNode.class), YangInstanceIdentifier.empty(), mountPoint))
+ .when(patchContext).getInstanceIdentifierContext();
+
+ // missing broker on mounted device
+ when(mountPoint.getService(DOMDataBroker.class)).thenReturn(Optional.empty());
+ when(mountPoint.getService(DOMSchemaService.class)).thenReturn(Optional.empty());
+
+ final PatchStatusContext status = brokerFacade.patchConfigurationDataWithinTransaction(patchContext);
+
+ // assert not successful operation with error
+ assertNotNull(status.getGlobalErrors());
+ assertEquals(1, status.getGlobalErrors().size());
+ assertEquals(ErrorType.APPLICATION, status.getGlobalErrors().get(0).getErrorType());
+ assertEquals(ErrorTag.OPERATION_FAILED, status.getGlobalErrors().get(0).getErrorTag());
+
+ assertFalse("Patch operation should fail on mounted device without Broker", status.isOk());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug3595Test.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug3595Test.java
new file mode 100644
index 0000000..0d7241d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug3595Test.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+public class Bug3595Test {
+
+ private static final QName CONT_QNAME = QName.create("leafref:module", "2014-04-17", "cont");
+ private static final QName LST_WITH_LFREF_KEY_QNAME = QName.create(CONT_QNAME, "lst-with-lfref-key");
+ private static final QName LFREF_KEY_QNAME = QName.create(CONT_QNAME, "lfref-key");
+ private static EffectiveModelContext schemaContext;
+
+ private final ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException {
+ schemaContext = TestUtils.loadSchemaContext("/leafref/yang");
+ Module module = TestUtils.findModule(schemaContext.getModules(), "leafref-module");
+ assertNotNull(module);
+ module = TestUtils.findModule(schemaContext.getModules(), "referenced-module");
+ assertNotNull(module);
+ }
+
+ @Test
+ public void testLeafrefListKeyDeserializtion() {
+ final YangInstanceIdentifier node1IIexpected = YangInstanceIdentifier.of(CONT_QNAME)
+ .node(LST_WITH_LFREF_KEY_QNAME).node(NodeIdentifierWithPredicates.of(
+ LST_WITH_LFREF_KEY_QNAME, LFREF_KEY_QNAME, "node1"));
+ final InstanceIdentifierContext iiContext =
+ controllerContext.toInstanceIdentifier("leafref-module:cont/lst-with-lfref-key/node1");
+ iiContext.getInstanceIdentifier();
+ assertEquals(node1IIexpected, iiContext.getInstanceIdentifier());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug8072Test.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug8072Test.java
new file mode 100644
index 0000000..a65babd
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug8072Test.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class Bug8072Test {
+ private static final String EXTERNAL_MODULE_NAME = "test-module";
+ private static final QName MODULES_QNAME = QName.create("test:module", "2014-01-09", "modules");
+ private static final QName MODULE_QNAME = QName.create("test:module", "2014-01-09", "module");
+ private static final QName NAME_QNAME = QName.create("test:module", "2014-01-09", "name");
+ private static final QName TYPE_QNAME = QName.create("test:module", "2014-01-09", "type");
+ private static final QName MODULE_TYPE_QNAME = QName.create("test:module", "2014-01-09", "module-type");
+
+ private static EffectiveModelContext schemaContext;
+
+ private final ControllerContext controllerContext;
+
+ public Bug8072Test() throws FileNotFoundException {
+ final EffectiveModelContext mountPointContext = TestUtils.loadSchemaContext("/full-versions/test-module");
+ final DOMMountPoint mountInstance = mock(DOMMountPoint.class);
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext, mountInstance);
+ doReturn(Optional.of(FixedDOMSchemaService.of(() -> mountPointContext))).when(mountInstance)
+ .getService(DOMSchemaService.class);
+ }
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs");
+ assertEquals(0, schemaContext.findModules(EXTERNAL_MODULE_NAME).size());
+ }
+
+ @Test
+ public void testIdentityRefFromExternalModule() throws FileNotFoundException, ReactorException {
+ final InstanceIdentifierContext ctx = controllerContext.toInstanceIdentifier(
+ "simple-nodes:users/yang-ext:mount/test-module:modules/module/test-module:module-type/name");
+
+ final Map<QName, Object> keyValues = new HashMap<>();
+ keyValues.put(NAME_QNAME, "name");
+ keyValues.put(TYPE_QNAME, MODULE_TYPE_QNAME);
+ final YangInstanceIdentifier expectedYII = YangInstanceIdentifier.of(MODULES_QNAME).node(MODULE_QNAME)
+ .node(NodeIdentifierWithPredicates.of(MODULE_QNAME, keyValues));
+
+ assertEquals(expectedYII, ctx.getInstanceIdentifier());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java
new file mode 100644
index 0000000..96100cb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import org.junit.BeforeClass;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ dataLoad("/instanceidentifier/yang", 4, "instance-identifier-module", "cont");
+ }
+
+
+ private static void validateXmlOutput(final String xml) throws XMLStreamException {
+ final XMLInputFactory xmlInFactory = XMLInputFactory.newInstance();
+ XMLEventReader eventReader;
+
+ eventReader = xmlInFactory.createXMLEventReader(new ByteArrayInputStream(xml.getBytes()));
+ String augmentAugmentModulePrefix = null;
+ String augmentModulePrefix = null;
+ String instanceIdentifierModulePrefix = null;
+ while (eventReader.hasNext()) {
+ final XMLEvent nextEvent = eventReader.nextEvent();
+ if (nextEvent.isStartElement()) {
+ final StartElement startElement = (StartElement) nextEvent;
+ if (startElement.getName().getLocalPart().equals("lf111")) {
+ final Iterator<?> prefixes =
+ startElement.getNamespaceContext().getPrefixes("augment:augment:module");
+
+ while (prefixes.hasNext() && augmentAugmentModulePrefix == null) {
+ final String prefix = (String) prefixes.next();
+ if (!prefix.isEmpty()) {
+ augmentAugmentModulePrefix = prefix;
+ }
+ }
+
+ augmentModulePrefix = startElement.getNamespaceContext().getPrefix("augment:module");
+ instanceIdentifierModulePrefix =
+ startElement.getNamespaceContext().getPrefix("instance:identifier:module");
+ break;
+ }
+ }
+ }
+
+ assertNotNull(augmentAugmentModulePrefix);
+ assertNotNull(augmentModulePrefix);
+ assertNotNull(instanceIdentifierModulePrefix);
+
+ final String instanceIdentifierValue = "/" + instanceIdentifierModulePrefix + ":cont/"
+ + instanceIdentifierModulePrefix + ":cont1/" + augmentModulePrefix + ":lst11[" + augmentModulePrefix
+ + ":keyvalue111='value1'][" + augmentModulePrefix + ":keyvalue112='value2']/"
+ + augmentAugmentModulePrefix + ":lf112";
+
+ assertTrue(xml.contains(instanceIdentifierValue));
+
+ }
+
+ private static void validateXmlOutputWithLeafList(final String xml) throws XMLStreamException {
+ final XMLInputFactory xmlInFactory = XMLInputFactory.newInstance();
+ XMLEventReader eventReader;
+
+ eventReader = xmlInFactory.createXMLEventReader(new ByteArrayInputStream(xml.getBytes()));
+ String augmentModuleLfLstPrefix = null;
+ String iiModulePrefix = null;
+ while (eventReader.hasNext()) {
+ final XMLEvent nextEvent = eventReader.nextEvent();
+ if (nextEvent.isStartElement()) {
+ final StartElement startElement = (StartElement) nextEvent;
+ if (startElement.getName().getLocalPart().equals("lf111")) {
+ final Iterator<?> prefixes =
+ startElement.getNamespaceContext().getPrefixes("augment:module:leaf:list");
+
+ while (prefixes.hasNext() && augmentModuleLfLstPrefix == null) {
+ final String prefix = (String) prefixes.next();
+ if (!prefix.isEmpty()) {
+ augmentModuleLfLstPrefix = prefix;
+ }
+ }
+ iiModulePrefix = startElement.getNamespaceContext().getPrefix("instance:identifier:module");
+ break;
+ }
+ }
+ }
+
+ assertNotNull(augmentModuleLfLstPrefix);
+ assertNotNull(iiModulePrefix);
+
+ final String instanceIdentifierValue = "/" + iiModulePrefix + ":cont/" + iiModulePrefix + ":cont1/"
+ + augmentModuleLfLstPrefix + ":lflst11[.='lflst11_1']";
+
+ assertTrue(xml.contains(instanceIdentifierValue));
+
+ }
+
+ private static YangInstanceIdentifier createInstanceIdentifier() {
+ final List<PathArgument> pathArguments = new ArrayList<>();
+ pathArguments.add(new NodeIdentifier(QName.create("instance:identifier:module", "cont")));
+ pathArguments.add(new NodeIdentifier(QName.create("instance:identifier:module", "cont1")));
+
+ final QName qName = QName.create("augment:module", "lst11");
+ final Map<QName, Object> keyValues = new HashMap<>();
+ keyValues.put(QName.create("augment:module", "keyvalue111"), "value1");
+ keyValues.put(QName.create("augment:module", "keyvalue112"), "value2");
+ final NodeIdentifierWithPredicates nodeIdentifierWithPredicates =
+ NodeIdentifierWithPredicates.of(qName, keyValues);
+ pathArguments.add(nodeIdentifierWithPredicates);
+
+ pathArguments.add(new NodeIdentifier(QName.create("augment:augment:module", "lf112")));
+
+ return YangInstanceIdentifier.create(pathArguments);
+ }
+
+ private static YangInstanceIdentifier createInstanceIdentifierWithLeafList() {
+ final List<PathArgument> pathArguments = new ArrayList<>();
+ pathArguments.add(new NodeIdentifier(QName.create("instance:identifier:module", "cont")));
+ pathArguments.add(new NodeIdentifier(QName.create("instance:identifier:module", "cont1")));
+ pathArguments.add(new NodeWithValue<>(QName.create("augment:module:leaf:list", "lflst11"), "lflst11_1"));
+
+ return YangInstanceIdentifier.create(pathArguments);
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java
new file mode 100644
index 0000000..2110848
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014, 2015 Brocade Communication Systems, Inc., Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.io.FileNotFoundException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class CodecsExceptionsCatchingTest extends JerseyTest {
+
+ private RestconfImpl restConf;
+ private ControllerContext controllerContext;
+
+ @Before
+ public void init() throws FileNotFoundException, ReactorException {
+ restConf = RestconfImpl.newInstance(mock(BrokerFacade.class), controllerContext);
+ controllerContext = TestRestconfUtils.newControllerContext(TestUtils.loadSchemaContext(
+ "/decoding-exception/yang"));
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restConf, new NormalizedNodeJsonBodyWriter(),
+ new NormalizedNodeXmlBodyWriter(), new XmlNormalizedNodeBodyReader(controllerContext),
+ new JsonNormalizedNodeBodyReader(controllerContext));
+ return resourceConfig;
+ }
+
+ @Test
+ @Ignore // TODO RestconfDocumentedExceptionMapper needs be fixed before
+ public void stringToNumberConversionError() {
+ final Response response = target("/config/number:cont").request(MediaType.APPLICATION_XML).put(
+ Entity.entity("<cont xmlns=\"number\"><lf>3f</lf></cont>", MediaType.APPLICATION_XML));
+ final String exceptionMessage = response.readEntity(String.class);
+ assertTrue(exceptionMessage.contains("invalid-value"));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CutDataToCorrectDepthTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CutDataToCorrectDepthTest.java
new file mode 100644
index 0000000..e379b3a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CutDataToCorrectDepthTest.java
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.WriterParameters;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.QueryParametersParser;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+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;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CutDataToCorrectDepthTest extends JerseyTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JerseyTest.class);
+
+ private static NormalizedNode depth1Cont;
+ private static NormalizedNode depth2Cont1;
+ private NormalizedNode globalPayload;
+ private static EffectiveModelContext schemaContextModules;
+
+ private final ControllerContext controllerContext =
+ TestRestconfUtils.newControllerContext(schemaContextModules, null);
+
+ @Path("/")
+ public class RestImpl {
+
+ @GET
+ @Path("/config/{identifier:.+}")
+ @Produces({ "application/json", "application/xml" })
+ public NormalizedNodeContext getData(@Encoded @PathParam("identifier") final String identifier,
+ @Context final UriInfo uriInfo) {
+
+ final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
+
+ NormalizedNode data = null;
+ if (identifier.equals("nested-module:depth1-cont/depth2-cont1")) {
+ data = depth2Cont1;
+ } else if (identifier.equals("nested-module:depth1-cont")) {
+ data = depth1Cont;
+ }
+
+ final WriterParameters writerParameters = QueryParametersParser.parseWriterParameters(uriInfo);
+ return new NormalizedNodeContext(iiWithData, data, writerParameters);
+ }
+
+ @GET
+ @Path("/operational/{identifier:.+}")
+ @Produces({ "application/json", "application/xml" })
+ public NormalizedNodeContext getDataOperational(@Encoded @PathParam("identifier") final String identifier,
+ @Context final UriInfo uriInfo) {
+ return getData(identifier, uriInfo);
+ }
+
+ @PUT
+ @Path("/config/{identifier:.+}")
+ @Consumes({ "application/json", "application/xml" })
+ public void normalizedData(@Encoded @PathParam("identifier") final String identifier,
+ final NormalizedNodeContext payload) throws InterruptedException {
+ LOG.info("Payload: {}.", payload);
+ LOG.info("Instance identifier of payload: {}.",
+ payload.getInstanceIdentifierContext().getInstanceIdentifier());
+ LOG.info("Data of payload: {}.", payload.getData());
+ globalPayload = payload.getData();
+ }
+
+ @PUT
+ @Path("/operational/{identifier:.+}")
+ @Consumes({ "application/json", "application/xml" })
+ public void normalizedDataOperational(@Encoded @PathParam("identifier") final String identifier,
+ final NormalizedNodeContext payload) throws InterruptedException {
+ normalizedData(identifier, payload);
+ }
+ }
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ schemaContextModules = TestUtils.loadSchemaContext("/modules");
+ final Module module = TestUtils.findModule(schemaContextModules.getModules(), "nested-module");
+ assertNotNull(module);
+
+ final UnkeyedListNode listAsUnkeyedList = unkeyedList(
+ "depth2-cont1",
+ unkeyedEntry("depth2-cont1",
+ container("depth3-cont1",
+ container("depth4-cont1", leaf("depth5-leaf1", "depth5-leaf1-value")),
+ leaf("depth4-leaf1", "depth4-leaf1-value")), leaf("depth3-leaf1", "depth3-leaf1-value")));
+
+ final MapNode listAsMap = mapNode(
+ "depth2-list2",
+ mapEntryNode("depth2-list2", 2, leaf("depth3-lf1-key", "depth3-lf1-key-value"),
+ leaf("depth3-lf2-key", "depth3-lf2-key-value"), leaf("depth3-lf3", "depth3-lf3-value")));
+
+ depth1Cont = container(
+ "depth1-cont",
+ listAsUnkeyedList,
+ listAsMap,
+ leafList("depth2-lfLst1", "depth2-lflst1-value1", "depth2-lflst1-value2", "depth2-lflst1-value3"),
+ container(
+ "depth2-cont2",
+ container("depth3-cont2",
+ container("depth4-cont2", leaf("depth5-leaf2", "depth5-leaf2-value")),
+ leaf("depth4-leaf2", "depth4-leaf2-value")), leaf("depth3-leaf2", "depth3-leaf2-value")),
+ leaf("depth2-leaf1", "depth2-leaf1-value"));
+
+ depth2Cont1 = listAsUnkeyedList;
+ }
+
+ // TODO: These tests should be fixed/rewriten because they fail randomly due to data not being de-serialized
+ // properly in readers
+ //@Test
+ public void getDataWithUriDepthParameterTest() throws WebApplicationException, IOException {
+ getDataWithUriDepthParameter("application/json");
+ getDataWithUriDepthParameter("application/xml");
+ }
+
+ public void getDataWithUriDepthParameter(final String mediaType) throws WebApplicationException, IOException {
+ Response response;
+
+ // Test config with depth 1
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "1").request(mediaType)
+ .get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth1());
+
+ // Test config with depth 2
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "2").request(mediaType)
+ .get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth2());
+
+ // Test config with depth 3
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "3").request(mediaType)
+ .get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth3());
+
+ // Test config with depth 4
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "4").request(mediaType)
+ .get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth4());
+
+ // Test config with depth 5
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "5").request(mediaType)
+ .get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth5());
+
+ // Test config with depth unbounded
+
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "unbounded")
+ .request(mediaType).get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth5());
+ }
+
+ private void txtDataToNormalizedNode(final Response response, final String mediaType, final String uri) {
+ final String responseStr = response.readEntity(String.class);
+ LOG.info("Response entity message: {}.", responseStr);
+ target(uri).request(mediaType).put(Entity.entity(responseStr, mediaType));
+ }
+
+ private void verifyResponse(final NormalizedNode nodeData) throws WebApplicationException, IOException {
+ assertNotNull(globalPayload);
+ assertEquals(globalPayload, nodeData);
+ globalPayload = null;
+ }
+
+ @Override
+ protected Application configure() {
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(new RestImpl());
+ resourceConfig.registerClasses(XmlNormalizedNodeBodyReader.class, NormalizedNodeXmlBodyWriter.class,
+ JsonNormalizedNodeBodyReader.class, NormalizedNodeJsonBodyWriter.class,
+ RestconfDocumentedExceptionMapper.class);
+ return resourceConfig;
+ }
+
+ private static LeafNode<?> leaf(final String localName, final Object value) {
+ return Builders.leafBuilder().withNodeIdentifier(toIdentifier(localName)).withValue(value).build();
+ }
+
+ private static ContainerNode container(final String localName, final DataContainerChild... children) {
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> containerBuilder =
+ Builders.containerBuilder();
+ for (final DataContainerChild child : children) {
+ containerBuilder.withChild(child);
+ }
+ containerBuilder.withNodeIdentifier(toIdentifier(localName));
+ return containerBuilder.build();
+ }
+
+ private static UnkeyedListNode unkeyedList(
+ final String localName,
+ final UnkeyedListEntryNode... entryNodes) {
+ final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> builder = Builders.unkeyedListBuilder();
+ final NodeIdentifier identifier = toIdentifier(localName);
+ builder.withNodeIdentifier(identifier);
+ for (final UnkeyedListEntryNode unkeyedListEntryNode : entryNodes) {
+ builder.withChild(unkeyedListEntryNode);
+ }
+ return builder.build();
+ }
+
+ private static UnkeyedListEntryNode unkeyedEntry(final String localName, final DataContainerChild... children) {
+ final DataContainerNodeBuilder<NodeIdentifier, UnkeyedListEntryNode> builder =
+ Builders.unkeyedListEntryBuilder();
+ builder.withNodeIdentifier(toIdentifier(localName));
+ for (final DataContainerChild child : children) {
+ builder.withChild(child);
+ }
+ return builder.build();
+ }
+
+ private static MapNode mapNode(final String localName, final MapEntryNode... entryNodes) {
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> builder = Builders.mapBuilder();
+ builder.withNodeIdentifier(toIdentifier(localName));
+ for (final MapEntryNode mapEntryNode : entryNodes) {
+ builder.withChild(mapEntryNode);
+ }
+ return builder.build();
+ }
+
+ private static MapEntryNode mapEntryNode(final String localName, final int keysNumber,
+ final DataContainerChild... children) {
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
+ Builders.mapEntryBuilder();
+ final Map<QName, Object> keys = new HashMap<>();
+ for (int i = 0; i < keysNumber; i++) {
+ keys.put(children[i].getIdentifier().getNodeType(), children[i].body());
+ }
+ builder.withNodeIdentifier(toIdentifier(localName, keys));
+
+ for (final DataContainerChild child : children) {
+ builder.withChild(child);
+ }
+ return builder.build();
+ }
+
+ private static LeafSetNode<?> leafList(final String localName, final String... children) {
+ final ListNodeBuilder<Object, SystemLeafSetNode<Object>> builder = Builders.leafSetBuilder();
+ builder.withNodeIdentifier(toIdentifier(localName));
+ for (final String child : children) {
+ builder.withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(toIdentifier(localName, child))
+ .withValue(child).build());
+ }
+ return builder.build();
+ }
+
+ private static NodeIdentifier toIdentifier(final String localName) {
+ return new NodeIdentifier(QName.create("urn:nested:module", "2014-06-03", localName));
+ }
+
+ private static NodeIdentifierWithPredicates toIdentifier(final String localName, final Map<QName, Object> keys) {
+ return NodeIdentifierWithPredicates.of(QName.create("urn:nested:module", "2014-06-03", localName), keys);
+ }
+
+ private static NodeWithValue<?> toIdentifier(final String localName, final Object value) {
+ return new NodeWithValue<>(QName.create("urn:nested:module", "2014-06-03", localName), value);
+ }
+
+ private static UnkeyedListEntryNode nodeDataDepth3Operational() {
+ return unkeyedEntry("depth2-cont1",
+ container("depth3-cont1", container("depth4-cont1"), leaf("depth4-leaf1", "depth4-leaf1-value")),
+ leaf("depth3-leaf1", "depth3-leaf1-value"));
+ }
+
+ private static ContainerNode nodeDataDepth5() {
+ return container(
+ "depth1-cont",
+ unkeyedList(
+ "depth2-cont1",
+ unkeyedEntry("depth2-cont1",
+ container("depth3-cont1",
+ container("depth4-cont1", leaf("depth5-leaf1", "depth5-leaf1-value")),
+ leaf("depth4-leaf1", "depth4-leaf1-value")),
+ leaf("depth3-leaf1", "depth3-leaf1-value"))),
+ mapNode("depth2-list2",
+ mapEntryNode("depth2-list2", 2, leaf("depth3-lf1-key", "depth3-lf1-key-value"),
+ leaf("depth3-lf2-key", "depth3-lf2-key-value"), leaf("depth3-lf3", "depth3-lf3-value"))),
+ leafList("depth2-lfLst1", "depth2-lflst1-value1", "depth2-lflst1-value2", "depth2-lflst1-value3"),
+ container(
+ "depth2-cont2",
+ container("depth3-cont2",
+ container("depth4-cont2", leaf("depth5-leaf2", "depth5-leaf2-value")),
+ leaf("depth4-leaf2", "depth4-leaf2-value")), leaf("depth3-leaf2", "depth3-leaf2-value")),
+ leaf("depth2-leaf1", "depth2-leaf1-value"));
+ }
+
+ private static ContainerNode nodeDataDepth4() {
+ return container(
+ "depth1-cont",
+ unkeyedList("depth2-cont1", nodeDataDepth3Operational()),
+ mapNode("depth2-list2",
+ mapEntryNode("depth2-list2", 2, leaf("depth3-lf1-key", "depth3-lf1-key-value"),
+ leaf("depth3-lf2-key", "depth3-lf2-key-value"), leaf("depth3-lf3", "depth3-lf3-value"))),
+ leafList("depth2-lfLst1", "depth2-lflst1-value1", "depth2-lflst1-value2", "depth2-lflst1-value3"),
+ container(
+ "depth2-cont2",
+ container("depth3-cont2", container("depth4-cont2"), leaf("depth4-leaf2", "depth4-leaf2-value")),
+ leaf("depth3-leaf2", "depth3-leaf2-value")), leaf("depth2-leaf1", "depth2-leaf1-value"));
+ }
+
+ private static ContainerNode nodeDataDepth3() {
+ return container(
+ "depth1-cont",
+ unkeyedList("depth2-cont1",
+ unkeyedEntry("depth2-cont1", container("depth3-cont1"), leaf("depth3-leaf1", "depth3-leaf1-value"))),
+ mapNode("depth2-list2",
+ mapEntryNode("depth2-list2", 2, leaf("depth3-lf1-key", "depth3-lf1-key-value"),
+ leaf("depth3-lf2-key", "depth3-lf2-key-value"), leaf("depth3-lf3", "depth3-lf3-value"))),
+ leafList("depth2-lfLst1", "depth2-lflst1-value1", "depth2-lflst1-value2", "depth2-lflst1-value3"),
+ container("depth2-cont2", container("depth3-cont2"), leaf("depth3-leaf2", "depth3-leaf2-value")),
+ leaf("depth2-leaf1", "depth2-leaf1-value"));
+ }
+
+ private static ContainerNode nodeDataDepth2() {
+ return container(
+ "depth1-cont",
+ unkeyedList("depth2-cont1", unkeyedEntry("depth2-cont1")),
+ mapNode("depth2-list2",
+ mapEntryNode("depth2-list2", 2, leaf("depth3-lf1-key", "depth3-lf1-key-value"),
+ leaf("depth3-lf2-key", "depth3-lf2-key-value"))), container("depth2-cont2"),
+// leafList("depth2-lfLst1"),
+ leaf("depth2-leaf1", "depth2-leaf1-value"));
+ }
+
+ private static ContainerNode nodeDataDepth1() {
+ return container("depth1-cont");
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java
new file mode 100644
index 0000000..30a0c50
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class DummyFuture<T> implements Future<RpcResult<T>> {
+
+ private final boolean cancel;
+ private final boolean isCancelled;
+ private final boolean isDone;
+ private final RpcResult<T> result;
+
+ public DummyFuture() {
+ cancel = false;
+ isCancelled = false;
+ isDone = false;
+ result = null;
+ }
+
+ private DummyFuture(final Builder<T> builder) {
+ cancel = builder.cancel;
+ isCancelled = builder.isCancelled;
+ isDone = builder.isDone;
+ result = builder.result;
+ }
+
+ @Override
+ public boolean cancel(final boolean mayInterruptIfRunning) {
+ return cancel;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return isCancelled;
+ }
+
+ @Override
+ public boolean isDone() {
+ return isDone;
+ }
+
+ @Override
+ public RpcResult<T> get() throws InterruptedException, ExecutionException {
+ return result;
+ }
+
+ @Override
+ public RpcResult<T> get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException,
+ TimeoutException {
+ return result;
+ }
+
+ public static class Builder<T> {
+
+ private boolean cancel;
+ private boolean isCancelled;
+ private boolean isDone;
+ private RpcResult<T> result;
+
+ public Builder<T> cancel(final boolean newCancel) {
+ this.cancel = newCancel;
+ return this;
+ }
+
+ public Builder<T> isCancelled(final boolean cancelled) {
+ this.isCancelled = cancelled;
+ return this;
+ }
+
+ public Builder<T> isDone(final boolean done) {
+ this.isDone = done;
+ return this;
+ }
+
+ public Builder<T> rpcResult(final RpcResult<T> newResult) {
+ this.result = newResult;
+ return this;
+ }
+
+ public Future<RpcResult<T>> build() {
+ return new DummyFuture<>(this);
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java
new file mode 100644
index 0000000..ff01937
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class DummyRpcResult<T> implements RpcResult<T> {
+
+ private final boolean isSuccessful;
+ private final T result;
+ private final List<RpcError> errors;
+
+ public DummyRpcResult() {
+ isSuccessful = false;
+ result = null;
+ errors = null;
+ }
+
+ private DummyRpcResult(final Builder<T> builder) {
+ isSuccessful = builder.isSuccessful;
+ result = builder.result;
+ errors = builder.errors;
+ }
+
+ @Override
+ public boolean isSuccessful() {
+ return isSuccessful;
+ }
+
+ @Override
+ public T getResult() {
+ return result;
+ }
+
+ @Override
+ public List<RpcError> getErrors() {
+ return errors;
+ }
+
+ public static class Builder<T> {
+ private boolean isSuccessful;
+ private T result;
+ private List<RpcError> errors;
+
+ public Builder<T> isSuccessful(final boolean successful) {
+ this.isSuccessful = successful;
+ return this;
+ }
+
+ public Builder<T> result(final T newResult) {
+ this.result = newResult;
+ return this;
+ }
+
+ public Builder<T> errors(final List<RpcError> newErrors) {
+ this.errors = newErrors;
+ return this;
+ }
+
+ public RpcResult<T> build() {
+ return new DummyRpcResult<>(this);
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java
new file mode 100644
index 0000000..af408e6
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.util.List;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+
+public class DummyType implements TypeDefinition<DummyType> {
+ QName dummyQName = TestUtils.buildQName("dummy type", "simple:uri", "2012-12-17");
+
+ @Override
+ public QName getQName() {
+ return dummyQName;
+ }
+
+ @Override
+ public Optional<String> getDescription() {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<String> getReference() {
+ return Optional.empty();
+ }
+
+ @Override
+ public Status getStatus() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public DummyType getBaseType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Optional<String> getUnits() {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<? extends Object> getDefaultValue() {
+ return Optional.empty();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ExpressionParserTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ExpressionParserTest.java
new file mode 100644
index 0000000..f4ed8f9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ExpressionParserTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.util.Collection;
+import java.util.Optional;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+public class ExpressionParserTest {
+
+ private Collection<File> xmls;
+
+ @Before
+ public void setup() throws Exception {
+ this.xmls = TestRestconfUtils.loadFiles("/notifications/xml/output/");
+ }
+
+ @Test
+ public void trueDownFilterTest() throws Exception {
+ final boolean parser =
+ parser("notification/data-changed-notification/data-change-event/data/toasterStatus='down'",
+ "data_change_notification_toaster_status_DOWN.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseDownFilterTest() throws Exception {
+ final boolean parser =
+ parser("notification/data-changed-notification/data-change-event/data/toasterStatus='up'",
+ "data_change_notification_toaster_status_DOWN.xml");
+ Assert.assertFalse(parser);
+ }
+
+ @Test
+ public void trueNumberEqualsFilterTest() throws Exception {
+ final boolean parser = parser(
+ "notification/data-changed-notification/data-change-event/data/toasterStatus=1",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseNumberEqualsFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus=0",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertFalse(parser);
+ }
+
+ @Test
+ public void trueNumberLessFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus<2",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseNumberLessFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus<0",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertFalse(parser);
+ }
+
+ @Test
+ public void trueNumberLessEqualsFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus<=2",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseNumberLessEqualsFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus<=-1",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertFalse(parser);
+ }
+
+ @Test
+ public void trueNumberGreaterFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus>0",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseNumberGreaterFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus>5",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertFalse(parser);
+ }
+
+ @Test
+ public void trueNumberGreaterEqualsFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus>=0",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseNumberGreaterEqualsFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus>=5",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertFalse(parser);
+ }
+
+ private boolean parser(final String filter, final String fileName) throws Exception {
+ File xml = null;
+ for (final File file : this.xmls) {
+ if (file.getName().equals(fileName)) {
+ xml = file;
+ }
+ }
+ final YangInstanceIdentifier path = Mockito.mock(YangInstanceIdentifier.class);
+ final PathArgument pathValue = NodeIdentifier.create(QName.create("module", "2016-12-14", "localName"));
+ Mockito.when(path.getLastPathArgument()).thenReturn(pathValue);
+ final ListenerAdapter listener = Notificator.createListener(path, "streamName", NotificationOutputType.JSON,
+ null);
+ listener.setQueryParams(Instant.now(), Optional.empty(), Optional.ofNullable(filter), false, false);
+
+ // FIXME: do not use reflection here
+ final Class<?> superclass = listener.getClass().getSuperclass().getSuperclass();
+ Method method = null;
+ for (final Method met : superclass.getDeclaredMethods()) {
+ if (met.getName().equals("parseFilterParam")) {
+ method = met;
+ }
+ }
+ if (method == null) {
+ throw new Exception("Methode parseFilterParam doesn't exist in " + superclass.getName());
+ }
+ method.setAccessible(true);
+ return (boolean) method.invoke(listener, readFile(xml));
+ }
+
+ private static String readFile(final File xml) throws IOException {
+ try (BufferedReader br = new BufferedReader(new FileReader(xml, StandardCharsets.UTF_8))) {
+ final StringBuilder sb = new StringBuilder();
+ String line = br.readLine();
+
+ while (line != null) {
+ sb.append(line);
+ sb.append("\n");
+ line = br.readLine();
+ }
+ return sb.toString();
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java
new file mode 100644
index 0000000..19386a1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2013, 2015 Brocade Communication Systems, Inc., Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
+
+import java.io.FileNotFoundException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.ErrorTags;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class InvokeRpcMethodTest {
+
+ private static UriInfo uriInfo;
+ private static EffectiveModelContext schemaContext;
+
+ private final RestconfImpl restconfImpl;
+ private final ControllerContext controllerContext;
+ private final BrokerFacade brokerFacade = mock(BrokerFacade.class);
+
+ public InvokeRpcMethodTest() {
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+ }
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs", "/invoke-rpc");
+ final Collection<? extends Module> allModules = schemaContext.getModules();
+ assertNotNull(allModules);
+ final Module module = TestUtils.resolveModule("invoke-rpc-module", allModules);
+ assertNotNull(module);
+
+ uriInfo = mock(UriInfo.class);
+ final MultivaluedMap<String, String> map = new MultivaluedHashMap<>();
+ map.put("prettyPrint", List.of("true"));
+ doReturn(map).when(uriInfo).getQueryParameters(any(Boolean.class));
+ }
+
+ /**
+ * Test method invokeRpc in RestconfImpl class tests if composite node as input parameter of method invokeRpc
+ * (second argument) is wrapped to parent composite node which has QName equals to QName of rpc (resolved from
+ * string - first argument).
+ */
+ @Test
+ public void invokeRpcMethodTest() {
+ controllerContext.findModuleNameByNamespace(XMLNamespace.of("invoke:rpc:module"));
+
+ final NormalizedNodeContext payload = prepareDomPayload();
+
+ final NormalizedNodeContext rpcResponse =
+ restconfImpl.invokeRpc("invoke-rpc-module:rpc-test", payload, uriInfo);
+ assertNotNull(rpcResponse);
+ assertNull(rpcResponse.getData());
+
+ }
+
+ private NormalizedNodeContext prepareDomPayload() {
+ final EffectiveModelContext schema = controllerContext.getGlobalSchema();
+ final Module rpcModule = schema.findModules("invoke-rpc-module").iterator().next();
+ assertNotNull(rpcModule);
+ final QName rpcQName = QName.create(rpcModule.getQNameModule(), "rpc-test");
+ RpcDefinition rpcSchemaNode = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcSchemaNode = rpc;
+ break;
+ }
+ }
+ assertNotNull(rpcSchemaNode);
+ final InputSchemaNode rpcInputSchemaNode = rpcSchemaNode.getInput();
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> container =
+ SchemaAwareBuilders.containerBuilder(rpcInputSchemaNode);
+
+ final QName contQName = QName.create(rpcModule.getQNameModule(), "cont");
+ final DataSchemaNode contSchemaNode = rpcInputSchemaNode.getDataChildByName(contQName);
+ assertTrue(contSchemaNode instanceof ContainerSchemaNode);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contNode =
+ SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) contSchemaNode);
+
+ final QName lfQName = QName.create(rpcModule.getQNameModule(), "lf");
+ final DataSchemaNode lfSchemaNode = ((ContainerSchemaNode) contSchemaNode).getDataChildByName(lfQName);
+ assertTrue(lfSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> lfNode =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) lfSchemaNode).withValue("any value").build();
+ contNode.withChild(lfNode);
+ container.withChild(contNode.build());
+
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofRpcInput(schema, rpcSchemaNode, null),
+ container.build());
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayloadRpc_FailNoErrors() {
+ final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+
+ doReturn(immediateFailedFluentFuture(new DOMRpcImplementationNotAvailableException("testExeption")))
+ .when(brokerFacade).invokeRpc(eq(qname), any());
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED,
+ Optional.empty(), Optional.empty());
+ }
+
+ void verifyRestconfDocumentedException(final RestconfDocumentedException restDocumentedException, final int index,
+ final ErrorType expErrorType, final ErrorTag expErrorTag, final Optional<String> expErrorMsg,
+ final Optional<String> expAppTag) {
+
+ final List<RestconfError> errors = restDocumentedException.getErrors();
+ assertTrue("RestconfError not found at index " + index, errors.size() > index);
+
+ RestconfError actual = errors.get(index);
+
+ assertEquals("getErrorType", expErrorType, actual.getErrorType());
+ assertEquals("getErrorTag", expErrorTag, actual.getErrorTag());
+ assertNotNull("getErrorMessage is null", actual.getErrorMessage());
+
+ if (expErrorMsg.isPresent()) {
+ assertEquals("getErrorMessage", expErrorMsg.get(), actual.getErrorMessage());
+ }
+
+ if (expAppTag.isPresent()) {
+ assertEquals("getErrorAppTag", expAppTag.get(), actual.getErrorAppTag());
+ }
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayloadRpc_FailWithRpcError() {
+ final List<RpcError> rpcErrors = List.of(
+ RpcResultBuilder.newError(ErrorType.TRANSPORT, new ErrorTag("bogusTag"), "foo"),
+ RpcResultBuilder.newWarning(ErrorType.RPC, ErrorTag.IN_USE, "bar", "app-tag", null, null));
+
+ final DOMRpcResult result = new DefaultDOMRpcResult(rpcErrors);
+ final QName path = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+ doReturn(immediateFluentFuture(result)).when(brokerFacade).invokeRpc(eq(path), any());
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+
+ // We are performing pass-through here of error-tag, hence the tag remains as specified, but we want to make
+ // sure the HTTP status remains the same as
+ final ErrorTag bogus = new ErrorTag("bogusTag");
+ verifyRestconfDocumentedException(ex, 0, ErrorType.TRANSPORT, bogus, Optional.of("foo"), Optional.empty());
+ assertEquals(ErrorTags.statusOf(ErrorTag.OPERATION_FAILED), ErrorTags.statusOf(bogus));
+
+ verifyRestconfDocumentedException(ex, 1, ErrorType.RPC, ErrorTag.IN_USE, Optional.of("bar"),
+ Optional.of("app-tag"));
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayload_Success() {
+ final NormalizedNode resultObj = null;
+ final DOMRpcResult expResult = new DefaultDOMRpcResult(resultObj);
+
+ final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(qname), any());
+
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo);
+ assertNotNull(output);
+ assertEquals(null, output.getData());
+ // additional validation in the fact that the restconfImpl does not
+ // throw an exception.
+ }
+
+ @Test
+ public void testInvokeRpcWithEmptyOutput() {
+ final ContainerNode resultObj = mock(ContainerNode.class);
+ doReturn(Set.of()).when(resultObj).body();
+ doCallRealMethod().when(resultObj).isEmpty();
+ final DOMRpcResult expResult = new DefaultDOMRpcResult(resultObj);
+
+ final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(qname), any());
+
+ WebApplicationException exceptionToBeThrown = assertThrows(WebApplicationException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+ assertEquals(Response.Status.NO_CONTENT.getStatusCode(), exceptionToBeThrown.getResponse().getStatus());
+ }
+
+ @Test
+ public void testInvokeRpcMethodWithBadMethodName() {
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:bad-method", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT,
+ Optional.empty(), Optional.empty());
+ }
+
+ @Test
+ @Ignore
+ public void testInvokeRpcMethodWithInput() {
+ final DOMRpcResult expResult = mock(DOMRpcResult.class);
+ final QName path = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast");
+
+ final Module rpcModule = schemaContext.findModules("toaster").iterator().next();
+ assertNotNull(rpcModule);
+ final QName rpcQName = QName.create(rpcModule.getQNameModule(), "make-toast");
+
+ RpcDefinition rpcDef = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcDef = rpc;
+ break;
+ }
+ }
+
+ assertNotNull(rpcDef);
+
+ final NormalizedNodeContext payload = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofLocalRpcInput(schemaContext, rpcDef),
+ SchemaAwareBuilders.containerBuilder(rpcDef.getInput()).build());
+
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(path), any(NormalizedNode.class));
+
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:make-toast", payload, uriInfo);
+ assertNotNull(output);
+ assertEquals(null, output.getData());
+ // additional validation in the fact that the restconfImpl does not
+ // throw an exception.
+ }
+
+ @Test
+ public void testThrowExceptionWhenSlashInModuleName() {
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster/slash", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ Optional.empty(), Optional.empty());
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayloadWithOutput_Success() {
+ final SchemaContext schema = controllerContext.getGlobalSchema();
+ final Module rpcModule = schema.findModules("toaster").iterator().next();
+ assertNotNull(rpcModule);
+ final QName rpcQName = QName.create(rpcModule.getQNameModule(), "testOutput");
+ final QName rpcOutputQName = QName.create(rpcModule.getQNameModule(),"output");
+
+ RpcDefinition rpcDef = null;
+ ContainerLike rpcOutputSchemaNode = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcOutputSchemaNode = rpc.getOutput();
+ rpcDef = rpc;
+ break;
+ }
+ }
+ assertNotNull(rpcDef);
+ assertNotNull(rpcOutputSchemaNode);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> containerBuilder =
+ SchemaAwareBuilders.containerBuilder(rpcOutputSchemaNode);
+ final DataSchemaNode leafSchema = rpcOutputSchemaNode
+ .getDataChildByName(QName.create(rpcModule.getQNameModule(), "textOut"));
+ assertTrue(leafSchema instanceof LeafSchemaNode);
+ final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) leafSchema);
+ leafBuilder.withValue("brm");
+ containerBuilder.withChild(leafBuilder.build());
+ final ContainerNode container = containerBuilder.build();
+
+ final DOMRpcResult result = new DefaultDOMRpcResult(container);
+
+ doReturn(immediateFluentFuture(result)).when(brokerFacade).invokeRpc(eq(rpcDef.getQName()), any());
+
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:testOutput", null, uriInfo);
+ assertNotNull(output);
+ assertNotNull(output.getData());
+ assertSame(container, output.getData());
+ assertNotNull(output.getInstanceIdentifierContext());
+ assertNotNull(output.getInstanceIdentifierContext().getSchemaContext());
+ }
+
+ /**
+ * Tests calling of RestConfImpl method invokeRpc. In the method there is searched rpc in remote schema context.
+ * This rpc is then executed.
+ * I wasn't able to simulate calling of rpc on remote device therefore this testing method raise method when rpc is
+ * invoked.
+ */
+ @Test
+ public void testMountedRpcCallNoPayload_Success() throws Exception {
+ // FIXME find how to use mockito for it
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java
new file mode 100644
index 0000000..48db5de
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
+
+import com.google.common.io.Resources;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Optional;
+import javax.ws.rs.core.Response.Status;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMRpcException;
+import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.JSONRestconfServiceImpl;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.restconf.common.patch.PatchStatusEntity;
+import org.opendaylight.yangtools.yang.common.OperationFailedException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+/**
+ * Unit tests for JSONRestconfServiceImpl.
+ *
+ * @author Thomas Pantelis
+ */
+@Deprecated
+public class JSONRestconfServiceImplTest {
+ static final String IETF_INTERFACES_NS = "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+ static final String IETF_INTERFACES_VERSION = "2013-07-04";
+ static final QName INTERFACES_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "interfaces");
+ static final QName INTERFACE_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "interface");
+ static final QName NAME_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "name");
+ static final QName TYPE_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "type");
+ static final QName ENABLED_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "enabled");
+ static final QName DESC_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "description");
+
+ static final String TEST_MODULE_NS = "test:module";
+ static final String TEST_MODULE_VERSION = "2014-01-09";
+ static final QName TEST_CONT_QNAME = QName.create(TEST_MODULE_NS, TEST_MODULE_VERSION, "cont");
+ static final QName TEST_CONT1_QNAME = QName.create(TEST_MODULE_NS, TEST_MODULE_VERSION, "cont1");
+ static final QName TEST_LF11_QNAME = QName.create(TEST_MODULE_NS, TEST_MODULE_VERSION, "lf11");
+ static final QName TEST_LF12_QNAME = QName.create(TEST_MODULE_NS, TEST_MODULE_VERSION, "lf12");
+
+ static final String TOASTER_MODULE_NS = "http://netconfcentral.org/ns/toaster";
+ static final String TOASTER_MODULE_VERSION = "2009-11-20";
+ static final QName TOASTER_DONENESS_QNAME =
+ QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "toasterDoneness");
+ static final QName TOASTER_TYPE_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "toasterToastType");
+ static final QName WHEAT_BREAD_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "wheat-bread");
+ static final QName MAKE_TOAST_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "make-toast");
+ static final QName CANCEL_TOAST_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "cancel-toast");
+ static final QName TEST_OUTPUT_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "testOutput");
+ static final QName TEXT_OUT_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "textOut");
+
+ private static EffectiveModelContext schemaContext;
+
+ private final BrokerFacade brokerFacade = mock(BrokerFacade.class);
+ private final DOMMountPoint mockMountPoint = mock(DOMMountPoint.class);
+ private JSONRestconfServiceImpl service;
+
+ @BeforeClass
+ public static void init() throws IOException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs");
+ }
+
+ @Before
+ public void setup() throws FileNotFoundException {
+ final EffectiveModelContext mountPointSchemaContext = TestUtils.loadSchemaContext("/full-versions/test-module");
+ final ControllerContext controllerContext =
+ TestRestconfUtils.newControllerContext(schemaContext, mockMountPoint);
+ doReturn(java.util.Optional.of(FixedDOMSchemaService.of(() -> mountPointSchemaContext))).when(mockMountPoint)
+ .getService(eq(DOMSchemaService.class));
+
+ service = new JSONRestconfServiceImpl(controllerContext,
+ RestconfImpl.newInstance(brokerFacade, controllerContext));
+ }
+
+ private static String loadData(final String path) throws IOException {
+ return Resources.asCharSource(JSONRestconfServiceImplTest.class.getResource(path),
+ StandardCharsets.UTF_8).read();
+ }
+
+ @Test
+ public void testPut() throws Exception {
+ final PutResult result = mock(PutResult.class);
+ when(brokerFacade.commitConfigurationDataPut(any(EffectiveModelContext.class),
+ any(YangInstanceIdentifier.class), any(NormalizedNode.class), isNull(), isNull()))
+ .thenReturn(result);
+ doReturn(CommitInfo.emptyFluentFuture()).when(result).getFutureOfPutData();
+ when(result.getStatus()).thenReturn(Status.OK);
+ final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
+ final String payload = loadData("/parts/ietf-interfaces_interfaces.json");
+ service.put(uriPath, payload);
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
+ verify(brokerFacade).commitConfigurationDataPut(any(EffectiveModelContext.class), capturedPath.capture(),
+ capturedNode.capture(), isNull(), isNull());
+
+ verifyPath(capturedPath.getValue(), INTERFACES_QNAME, INTERFACE_QNAME,
+ new Object[]{INTERFACE_QNAME, NAME_QNAME, "eth0"});
+
+ assertTrue("Expected MapEntryNode. Actual " + capturedNode.getValue().getClass(),
+ capturedNode.getValue() instanceof MapEntryNode);
+ final MapEntryNode actualNode = (MapEntryNode) capturedNode.getValue();
+ assertEquals("MapEntryNode node type", INTERFACE_QNAME, actualNode.getIdentifier().getNodeType());
+ verifyLeafNode(actualNode, NAME_QNAME, "eth0");
+ verifyLeafNode(actualNode, TYPE_QNAME, "ethernetCsmacd");
+ verifyLeafNode(actualNode, ENABLED_QNAME, Boolean.FALSE);
+ verifyLeafNode(actualNode, DESC_QNAME, "some interface");
+ }
+
+ @Test
+ public void testPutBehindMountPoint() throws Exception {
+ final PutResult result = mock(PutResult.class);
+ when(brokerFacade.commitMountPointDataPut(any(DOMMountPoint.class),
+ any(YangInstanceIdentifier.class), any(NormalizedNode.class), isNull(), isNull()))
+ .thenReturn(result);
+ doReturn(CommitInfo.emptyFluentFuture()).when(result).getFutureOfPutData();
+ when(result.getStatus()).thenReturn(Status.OK);
+ final String uriPath = "ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1";
+ final String payload = loadData("/full-versions/testCont1Data.json");
+
+ service.put(uriPath, payload);
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
+ verify(brokerFacade).commitMountPointDataPut(same(mockMountPoint), capturedPath.capture(),
+ capturedNode.capture(), isNull(), isNull());
+
+ verifyPath(capturedPath.getValue(), TEST_CONT_QNAME, TEST_CONT1_QNAME);
+
+ assertTrue("Expected ContainerNode", capturedNode.getValue() instanceof ContainerNode);
+ final ContainerNode actualNode = (ContainerNode) capturedNode.getValue();
+ assertEquals("ContainerNode node type", TEST_CONT1_QNAME, actualNode.getIdentifier().getNodeType());
+ verifyLeafNode(actualNode, TEST_LF11_QNAME, "lf11 data");
+ verifyLeafNode(actualNode, TEST_LF12_QNAME, "lf12 data");
+ }
+
+ @Test(expected = OperationFailedException.class)
+ @SuppressWarnings("checkstyle:IllegalThrows")
+ public void testPutFailure() throws Throwable {
+ final PutResult result = mock(PutResult.class);
+
+ doReturn(immediateFailedFluentFuture(new TransactionCommitFailedException("mock"))).when(result)
+ .getFutureOfPutData();
+ when(result.getStatus()).thenReturn(Status.OK);
+ when(brokerFacade.commitConfigurationDataPut(any(EffectiveModelContext.class),
+ any(YangInstanceIdentifier.class), any(NormalizedNode.class), anyString(),
+ anyString())).thenReturn(result);
+
+ final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
+ final String payload = loadData("/parts/ietf-interfaces_interfaces.json");
+
+ service.put(uriPath, payload);
+ }
+
+ @Test
+ public void testPost() throws Exception {
+ doReturn(CommitInfo.emptyFluentFuture()).when(brokerFacade).commitConfigurationDataPost(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class),
+ isNull(), isNull());
+
+ final String uriPath = null;
+ final String payload = loadData("/parts/ietf-interfaces_interfaces_absolute_path.json");
+
+ service.post(uriPath, payload);
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
+ verify(brokerFacade).commitConfigurationDataPost(any(EffectiveModelContext.class), capturedPath.capture(),
+ capturedNode.capture(), isNull(), isNull());
+
+ verifyPath(capturedPath.getValue(), INTERFACES_QNAME);
+
+ assertTrue("Expected ContainerNode", capturedNode.getValue() instanceof ContainerNode);
+ final ContainerNode actualNode = (ContainerNode) capturedNode.getValue();
+ assertEquals("ContainerNode node type", INTERFACES_QNAME, actualNode.getIdentifier().getNodeType());
+
+ final java.util.Optional<DataContainerChild> mapChild = actualNode.findChildByArg(
+ new NodeIdentifier(INTERFACE_QNAME));
+ assertEquals(INTERFACE_QNAME.toString() + " present", true, mapChild.isPresent());
+ assertTrue("Expected MapNode. Actual " + mapChild.get().getClass(), mapChild.get() instanceof MapNode);
+ final MapNode mapNode = (MapNode)mapChild.get();
+
+ final NodeIdentifierWithPredicates entryNodeID = NodeIdentifierWithPredicates.of(
+ INTERFACE_QNAME, NAME_QNAME, "eth0");
+ final java.util.Optional<MapEntryNode> entryChild = mapNode.findChildByArg(entryNodeID);
+ assertEquals(entryNodeID.toString() + " present", true, entryChild.isPresent());
+ final MapEntryNode entryNode = entryChild.get();
+ verifyLeafNode(entryNode, NAME_QNAME, "eth0");
+ verifyLeafNode(entryNode, TYPE_QNAME, "ethernetCsmacd");
+ verifyLeafNode(entryNode, ENABLED_QNAME, Boolean.FALSE);
+ verifyLeafNode(entryNode, DESC_QNAME, "some interface");
+ }
+
+ @Test
+ public void testPostBehindMountPoint() throws Exception {
+ doReturn(CommitInfo.emptyFluentFuture()).when(brokerFacade).commitConfigurationDataPost(
+ any(DOMMountPoint.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class),
+ isNull(), isNull());
+
+ final String uriPath = "ietf-interfaces:interfaces/yang-ext:mount/test-module:cont";
+ final String payload = loadData("/full-versions/testCont1Data.json");
+
+ service.post(uriPath, payload);
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
+ verify(brokerFacade).commitConfigurationDataPost(same(mockMountPoint), capturedPath.capture(),
+ capturedNode.capture(), isNull(), isNull());
+
+ verifyPath(capturedPath.getValue(), TEST_CONT_QNAME, TEST_CONT1_QNAME);
+
+ assertTrue("Expected ContainerNode", capturedNode.getValue() instanceof ContainerNode);
+ final ContainerNode actualNode = (ContainerNode) capturedNode.getValue();
+ assertEquals("ContainerNode node type", TEST_CONT1_QNAME, actualNode.getIdentifier().getNodeType());
+ verifyLeafNode(actualNode, TEST_LF11_QNAME, "lf11 data");
+ verifyLeafNode(actualNode, TEST_LF12_QNAME, "lf12 data");
+ }
+
+ @Test(expected = TransactionCommitFailedException.class)
+ @SuppressWarnings({ "checkstyle:IllegalThrows", "checkstyle:avoidHidingCauseException" })
+ public void testPostFailure() throws Throwable {
+ doReturn(immediateFailedFluentFuture(new TransactionCommitFailedException("mock"))).when(brokerFacade)
+ .commitConfigurationDataPost(any(EffectiveModelContext.class), any(YangInstanceIdentifier.class),
+ any(NormalizedNode.class), isNull(), isNull());
+
+ final String uriPath = null;
+ final String payload = loadData("/parts/ietf-interfaces_interfaces_absolute_path.json");
+
+ try {
+ service.post(uriPath, payload);
+ } catch (final OperationFailedException e) {
+ assertNotNull(e.getCause());
+ throw e.getCause();
+ }
+ }
+
+ @Test
+ public void testPatch() throws Exception {
+ final PatchStatusContext result = mock(PatchStatusContext.class);
+ when(brokerFacade.patchConfigurationDataWithinTransaction(any(PatchContext.class)))
+ .thenReturn(result);
+
+ when(result.getEditCollection()).thenReturn(List.of(new PatchStatusEntity("edit1", true, null)));
+ when(result.getGlobalErrors()).thenReturn(List.of());
+ when(result.getPatchId()).thenReturn("1");
+ final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
+ final String payload = loadData("/parts/ietf-interfaces_interfaces_patch.json");
+ final Optional<String> patchResult = service.patch(uriPath, payload);
+
+ assertTrue(patchResult.get().contains("\"ok\":[null]"));
+ }
+
+ @Test
+ public void testPatchBehindMountPoint() throws Exception {
+ final PatchStatusContext result = mock(PatchStatusContext.class);
+ when(brokerFacade.patchConfigurationDataWithinTransaction(any(PatchContext.class))).thenReturn(result);
+
+ when(result.getEditCollection()).thenReturn(List.of(new PatchStatusEntity("edit1", true, null)));
+ when(result.getGlobalErrors()).thenReturn(List.of());
+ when(result.getPatchId()).thenReturn("1");
+
+ final String uriPath = "ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1";
+ final String payload = loadData("/full-versions/testCont1DataPatch.json");
+
+ final Optional<String> patchResult = service.patch(uriPath, payload);
+
+ assertTrue(patchResult.get().contains("\"ok\":[null]"));
+ }
+
+ @Test(expected = OperationFailedException.class)
+ @SuppressWarnings("checkstyle:IllegalThrows")
+ public void testPatchFailure() throws Throwable {
+ final PatchStatusContext result = mock(PatchStatusContext.class);
+ when(brokerFacade.patchConfigurationDataWithinTransaction(any(PatchContext.class)))
+ .thenThrow(new TransactionCommitFailedException("Transaction failed"));
+
+ final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
+ final String payload = loadData("/parts/ietf-interfaces_interfaces_patch.json");
+
+ final Optional<String> patchResult = service.patch(uriPath, payload);
+
+ assertTrue("Patch output is not null", patchResult.isPresent());
+ String patch = patchResult.get();
+ assertTrue(patch.contains("TransactionCommitFailedException"));
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ doReturn(CommitInfo.emptyFluentFuture()).when(brokerFacade)
+ .commitConfigurationDataDelete(any(YangInstanceIdentifier.class));
+
+ final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
+
+ service.delete(uriPath);
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ verify(brokerFacade).commitConfigurationDataDelete(capturedPath.capture());
+
+ verifyPath(capturedPath.getValue(), INTERFACES_QNAME, INTERFACE_QNAME,
+ new Object[]{INTERFACE_QNAME, NAME_QNAME, "eth0"});
+ }
+
+ @Test(expected = OperationFailedException.class)
+ public void testDeleteFailure() throws Exception {
+ final String invalidUriPath = "ietf-interfaces:interfaces/invalid";
+
+ service.delete(invalidUriPath);
+ }
+
+ @Test
+ public void testGetConfig() throws Exception {
+ testGet(LogicalDatastoreType.CONFIGURATION);
+ }
+
+ @Test
+ public void testGetOperational() throws Exception {
+ testGet(LogicalDatastoreType.OPERATIONAL);
+ }
+
+ @Test
+ public void testGetWithNoData() throws OperationFailedException {
+ doReturn(null).when(brokerFacade).readConfigurationData(any(YangInstanceIdentifier.class), anyString());
+ final String uriPath = "ietf-interfaces:interfaces";
+ service.get(uriPath, LogicalDatastoreType.CONFIGURATION);
+ }
+
+ @Test(expected = OperationFailedException.class)
+ public void testGetFailure() throws Exception {
+ final String invalidUriPath = "/ietf-interfaces:interfaces/invalid";
+ service.get(invalidUriPath, LogicalDatastoreType.CONFIGURATION);
+ }
+
+ @Test
+ public void testInvokeRpcWithInput() throws Exception {
+ final DOMRpcResult expResult = new DefaultDOMRpcResult((NormalizedNode)null);
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(MAKE_TOAST_QNAME),
+ any(NormalizedNode.class));
+
+ final String uriPath = "toaster:make-toast";
+ final String input = loadData("/full-versions/make-toast-rpc-input.json");
+
+ final Optional<String> output = service.invokeRpc(uriPath, Optional.of(input));
+
+ assertEquals("Output present", false, output.isPresent());
+
+ final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
+ verify(brokerFacade).invokeRpc(eq(MAKE_TOAST_QNAME), capturedNode.capture());
+
+ assertTrue("Expected ContainerNode. Actual " + capturedNode.getValue().getClass(),
+ capturedNode.getValue() instanceof ContainerNode);
+ final ContainerNode actualNode = (ContainerNode) capturedNode.getValue();
+ verifyLeafNode(actualNode, TOASTER_DONENESS_QNAME, Uint32.valueOf(10));
+ verifyLeafNode(actualNode, TOASTER_TYPE_QNAME, WHEAT_BREAD_QNAME);
+ }
+
+ @Test
+ public void testInvokeRpcWithNoInput() throws Exception {
+ final DOMRpcResult expResult = new DefaultDOMRpcResult((NormalizedNode)null);
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(any(QName.class), any());
+
+ final String uriPath = "toaster:cancel-toast";
+
+ final Optional<String> output = service.invokeRpc(uriPath, Optional.empty());
+
+ assertEquals("Output present", false, output.isPresent());
+
+ verify(brokerFacade).invokeRpc(eq(CANCEL_TOAST_QNAME), any());
+ }
+
+ @Test
+ public void testInvokeRpcWithOutput() throws Exception {
+ final NormalizedNode outputNode = ImmutableContainerNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TEST_OUTPUT_QNAME))
+ .withChild(ImmutableNodes.leafNode(TEXT_OUT_QNAME, "foo")).build();
+ final DOMRpcResult expResult = new DefaultDOMRpcResult(outputNode);
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(any(QName.class), any());
+
+ final String uriPath = "toaster:testOutput";
+
+ final Optional<String> output = service.invokeRpc(uriPath, Optional.empty());
+
+ assertEquals("Output present", true, output.isPresent());
+ assertNotNull("Returned null response", output.get());
+ assertThat("Missing \"textOut\"", output.get(), containsString("\"textOut\":\"foo\""));
+
+ verify(brokerFacade).invokeRpc(eq(TEST_OUTPUT_QNAME), any());
+ }
+
+ @Test(expected = OperationFailedException.class)
+ public void testInvokeRpcFailure() throws Exception {
+ final DOMRpcException exception = new DOMRpcImplementationNotAvailableException("testExeption");
+ doReturn(immediateFailedFluentFuture(exception)).when(brokerFacade).invokeRpc(any(QName.class),
+ any(NormalizedNode.class));
+
+ final String uriPath = "toaster:cancel-toast";
+
+ service.invokeRpc(uriPath, Optional.empty());
+ }
+
+ void testGet(final LogicalDatastoreType datastoreType) throws OperationFailedException {
+ final MapEntryNode entryNode = ImmutableNodes.mapEntryBuilder(INTERFACE_QNAME, NAME_QNAME, "eth0")
+ .withChild(ImmutableNodes.leafNode(NAME_QNAME, "eth0"))
+ .withChild(ImmutableNodes.leafNode(TYPE_QNAME, "ethernetCsmacd"))
+ .withChild(ImmutableNodes.leafNode(ENABLED_QNAME, Boolean.TRUE))
+ .withChild(ImmutableNodes.leafNode(DESC_QNAME, "eth interface"))
+ .build();
+
+ if (datastoreType == LogicalDatastoreType.CONFIGURATION) {
+ doReturn(entryNode).when(brokerFacade).readConfigurationData(any(YangInstanceIdentifier.class),
+ isNull());
+ } else {
+ doReturn(entryNode).when(brokerFacade).readOperationalData(any(YangInstanceIdentifier.class));
+ }
+
+ final String uriPath = "/ietf-interfaces:interfaces/interface/eth0";
+
+ final Optional<String> optionalResp = service.get(uriPath, datastoreType);
+ assertEquals("Response present", true, optionalResp.isPresent());
+ final String jsonResp = optionalResp.get();
+
+ assertNotNull("Returned null response", jsonResp);
+ assertThat("Missing \"name\"", jsonResp, containsString("\"name\":\"eth0\""));
+ assertThat("Missing \"type\"", jsonResp, containsString("\"type\":\"ethernetCsmacd\""));
+ assertThat("Missing \"enabled\"", jsonResp, containsString("\"enabled\":true"));
+ assertThat("Missing \"description\"", jsonResp, containsString("\"description\":\"eth interface\""));
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ if (datastoreType == LogicalDatastoreType.CONFIGURATION) {
+ verify(brokerFacade).readConfigurationData(capturedPath.capture(), isNull());
+ } else {
+ verify(brokerFacade).readOperationalData(capturedPath.capture());
+ }
+
+ verifyPath(capturedPath.getValue(), INTERFACES_QNAME, INTERFACE_QNAME,
+ new Object[]{INTERFACE_QNAME, NAME_QNAME, "eth0"});
+ }
+
+ void verifyLeafNode(final DataContainerNode parent, final QName leafType, final Object leafValue) {
+ final java.util.Optional<DataContainerChild> leafChild = parent.findChildByArg(new NodeIdentifier(leafType));
+ assertTrue(leafType.toString() + " present", leafChild.isPresent());
+ assertEquals(leafType.toString() + " value", leafValue, leafChild.get().body());
+ }
+
+ void verifyPath(final YangInstanceIdentifier path, final Object... expArgs) {
+ final List<PathArgument> pathArgs = path.getPathArguments();
+ assertEquals("Arg count for actual path " + path, expArgs.length, pathArgs.size());
+ int index = 0;
+ for (final PathArgument actual: pathArgs) {
+ QName expNodeType;
+ if (expArgs[index] instanceof Object[]) {
+ final Object[] listEntry = (Object[]) expArgs[index];
+ expNodeType = (QName) listEntry[0];
+
+ assertTrue(actual instanceof NodeIdentifierWithPredicates);
+ final NodeIdentifierWithPredicates nip = (NodeIdentifierWithPredicates)actual;
+ assertEquals(String.format("Path arg %d keyValues size", index + 1), 1, nip.size());
+ final QName expKey = (QName) listEntry[1];
+ assertEquals(String.format("Path arg %d keyValue for %s", index + 1, expKey), listEntry[2],
+ nip.getValue(expKey));
+ } else {
+ expNodeType = (QName) expArgs[index];
+ }
+
+ assertEquals(String.format("Path arg %d node type", index + 1), expNodeType, actual.getNodeType());
+ index++;
+ }
+
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java
new file mode 100644
index 0000000..2bddec2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.JSON;
+import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.XML;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+
+public class MediaTypesTest extends JerseyTest {
+
+ private static String jsonData;
+ private static String xmlData;
+
+ private RestconfService restconfService;
+
+ @BeforeClass
+ public static void init() throws IOException {
+ final String jsonPath = RestconfImplTest.class.getResource("/parts/ietf-interfaces_interfaces.json").getPath();
+ jsonData = TestUtils.loadTextFile(jsonPath);
+ final InputStream xmlStream =
+ RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+ xmlData = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream));
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());'
+ restconfService = mock(RestconfService.class);
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfService, new NormalizedNodeJsonBodyWriter(),
+ new NormalizedNodeXmlBodyWriter());
+ return resourceConfig;
+ }
+
+ @Test
+ @Ignore
+ public void testPostOperationsWithInputDataMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/operations/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ when(restconfService.invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class)))
+ .thenReturn(null);
+ post(uri, Draft02.MediaTypes.OPERATION + JSON, Draft02.MediaTypes.OPERATION + JSON, jsonData);
+ verify(restconfService, times(1)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, Draft02.MediaTypes.OPERATION + XML, Draft02.MediaTypes.OPERATION + XML, xmlData);
+ verify(restconfService, times(2)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, jsonData);
+ verify(restconfService, times(3)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, MediaType.APPLICATION_XML, MediaType.APPLICATION_XML, xmlData);
+ verify(restconfService, times(4)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, MediaType.TEXT_XML, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(5)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+
+ // negative tests
+ post(uri, MediaType.TEXT_PLAIN, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, MediaType.TEXT_XML, MediaType.TEXT_PLAIN, xmlData);
+ verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ }
+
+ @Test
+ public void testGetConfigMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/config/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ when(restconfService.readConfigurationData(eq(uriPath), any(UriInfo.class))).thenReturn(null);
+ get(uri, Draft02.MediaTypes.DATA + JSON);
+ verify(restconfService, times(1)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+ get(uri, Draft02.MediaTypes.DATA + XML);
+ verify(restconfService, times(2)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.APPLICATION_JSON);
+ verify(restconfService, times(3)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.APPLICATION_XML);
+ verify(restconfService, times(4)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.TEXT_XML);
+ verify(restconfService, times(5)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+
+ // negative tests
+ get(uri, MediaType.TEXT_PLAIN);
+ verify(restconfService, times(5)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+ }
+
+ @Test
+ public void testGetOperationalMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/operational/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ when(restconfService.readOperationalData(eq(uriPath), any(UriInfo.class))).thenReturn(null);
+ get(uri, Draft02.MediaTypes.DATA + JSON);
+ verify(restconfService, times(1)).readOperationalData(eq(uriPath), any(UriInfo.class));
+ get(uri, Draft02.MediaTypes.DATA + XML);
+ verify(restconfService, times(2)).readOperationalData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.APPLICATION_JSON);
+ verify(restconfService, times(3)).readOperationalData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.APPLICATION_XML);
+ verify(restconfService, times(4)).readOperationalData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.TEXT_XML);
+ verify(restconfService, times(5)).readOperationalData(eq(uriPath), any(UriInfo.class));
+
+ // negative tests
+ get(uri, MediaType.TEXT_PLAIN);
+ verify(restconfService, times(5)).readOperationalData(eq(uriPath), any(UriInfo.class));
+ }
+
+ @Test
+ @Ignore
+ public void testPutConfigMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/config/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ when(restconfService.updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class), uriInfo))
+ .thenReturn(null);
+ put(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData);
+ verify(restconfService, times(1)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ put(uri, null, Draft02.MediaTypes.DATA + XML, xmlData);
+ verify(restconfService, times(2)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ put(uri, null, MediaType.APPLICATION_JSON, jsonData);
+ verify(restconfService, times(3)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ put(uri, null, MediaType.APPLICATION_XML, xmlData);
+ verify(restconfService, times(4)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ put(uri, null, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(5)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ put(uri, "fooMediaType", MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ }
+
+ @Test
+ @Ignore
+ public void testPostConfigWithPathMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/config/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ when(restconfService.createConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ any(UriInfo.class))).thenReturn(null);
+ post(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData);
+ verify(restconfService, times(1)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, Draft02.MediaTypes.DATA + XML, xmlData);
+ verify(restconfService, times(2)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.APPLICATION_JSON, jsonData);
+ verify(restconfService, times(3)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.APPLICATION_XML, xmlData);
+ verify(restconfService, times(4)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(5)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, "fooMediaType", MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ }
+
+ @Test
+ @Ignore
+ public void testPostConfigMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/config/";
+ final String uri = uriPrefix;
+ when(restconfService.createConfigurationData(any(NormalizedNodeContext.class),
+ any(UriInfo.class))).thenReturn(null);
+ post(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData);
+ verify(restconfService, times(1)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, Draft02.MediaTypes.DATA + XML, xmlData);
+ verify(restconfService, times(2)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.APPLICATION_JSON, jsonData);
+ verify(restconfService, times(3)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.APPLICATION_XML, xmlData);
+ verify(restconfService, times(4)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(5)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, "fooMediaType", MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ }
+
+ @Test
+ public void testDeleteConfigMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/config/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ when(restconfService.deleteConfigurationData(eq(uriPath))).thenReturn(null);
+ target(uri).request("fooMediaType").delete();
+ verify(restconfService, times(1)).deleteConfigurationData(uriPath);
+ }
+
+ private int get(final String uri, final String acceptMediaType) {
+ return target(uri).request(acceptMediaType).get().getStatus();
+ }
+
+ private int put(final String uri, final String acceptMediaType, final String contentTypeMediaType,
+ final String data) {
+ if (acceptMediaType == null) {
+ return target(uri).request().put(Entity.entity(data, contentTypeMediaType)).getStatus();
+ }
+ return target(uri).request(acceptMediaType).put(Entity.entity(data, contentTypeMediaType)).getStatus();
+ }
+
+ private int post(final String uri, final String acceptMediaType, final String contentTypeMediaType,
+ final String data) {
+ if (acceptMediaType == null) {
+ if (contentTypeMediaType == null || data == null) {
+ return target(uri).request().post(null).getStatus();
+ }
+ return target(uri).request().post(Entity.entity(data, contentTypeMediaType)).getStatus();
+ }
+ if (contentTypeMediaType == null || data == null) {
+ return target(uri).request(acceptMediaType).post(null).getStatus();
+ }
+ return target(uri).request(acceptMediaType).post(Entity.entity(data, contentTypeMediaType)).getStatus();
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java
new file mode 100644
index 0000000..3af5f96
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class NormalizeNodeTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialization() throws FileNotFoundException, ReactorException {
+ dataLoad("/normalize-node/yang/");
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java
new file mode 100644
index 0000000..bd2d48b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+import org.opendaylight.netconf.sal.restconf.impl.RestCodec;
+import org.opendaylight.yangtools.concepts.IllegalArgumentCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.ri.type.BaseTypes;
+
+public class RestCodecExceptionsTest {
+ @Test
+ public void serializeExceptionTest() {
+ final IllegalArgumentCodec<Object, Object> codec = RestCodec.from(
+ BaseTypes.bitsTypeBuilder(QName.create("test", "2014-05-30", "test")).build(), null, null);
+ final String serializedValue = (String) codec.serialize("incorrect value"); // set
+ // expected
+ assertEquals("incorrect value", serializedValue);
+ }
+
+ @Test
+ public void deserializeExceptionTest() {
+ final IdentityrefTypeDefinition mockedIidentityrefType = mock(IdentityrefTypeDefinition.class);
+
+ final IllegalArgumentCodec<Object, Object> codec = RestCodec.from(mockedIidentityrefType, null, null);
+ assertNull(codec.deserialize("incorrect value"));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java
new file mode 100644
index 0000000..3ebbf28
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
+
+import java.io.FileNotFoundException;
+import java.io.UnsupportedEncodingException;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class RestDeleteOperationTest extends JerseyTest {
+ private static EffectiveModelContext schemaContext;
+
+ private ControllerContext controllerContext;
+ private BrokerFacade brokerFacade;
+ private RestconfImpl restconfImpl;
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/test-config-data/yang1");
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ controllerContext.setSchemas(schemaContext);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl, new NormalizedNodeJsonBodyWriter(),
+ new NormalizedNodeXmlBodyWriter(), new XmlNormalizedNodeBodyReader(controllerContext),
+ new JsonNormalizedNodeBodyReader(controllerContext),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ @Test
+ public void deleteConfigStatusCodes() throws UnsupportedEncodingException {
+ final String uri = "/config/test-interface:interfaces";
+ doReturn(CommitInfo.emptyFluentFuture()).when(brokerFacade)
+ .commitConfigurationDataDelete(any(YangInstanceIdentifier.class));
+ Response response = target(uri).request(MediaType.APPLICATION_XML).delete();
+ assertEquals(200, response.getStatus());
+
+ doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataDelete(
+ any(YangInstanceIdentifier.class));
+ response = target(uri).request(MediaType.APPLICATION_XML).delete();
+ assertEquals(500, response.getStatus());
+ }
+
+ @Test
+ public void deleteFailTest() throws Exception {
+ final String uri = "/config/test-interface:interfaces";
+ doReturn(immediateFailedFluentFuture(new TransactionCommitFailedException("failed test"))).when(brokerFacade)
+ .commitConfigurationDataDelete(any(YangInstanceIdentifier.class));
+ final Response response = target(uri).request(MediaType.APPLICATION_XML).delete();
+ assertEquals(500, response.getStatus());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java
new file mode 100644
index 0000000..d0b30cb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class RestGetAugmentedElementWhenEqualNamesTest {
+
+ private static EffectiveModelContext schemaContext;
+
+ private final ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ schemaContext = TestUtils.loadSchemaContext("/common/augment/yang");
+ }
+
+ @Test
+ public void augmentedNodesInUri() {
+ InstanceIdentifierContext iiWithData =
+ controllerContext.toInstanceIdentifier("main:cont/augment-main-a:cont1");
+ assertEquals(XMLNamespace.of("ns:augment:main:a"), iiWithData.getSchemaNode().getQName().getNamespace());
+ iiWithData = controllerContext.toInstanceIdentifier("main:cont/augment-main-b:cont1");
+ assertEquals(XMLNamespace.of("ns:augment:main:b"), iiWithData.getSchemaNode().getQName().getNamespace());
+ }
+
+ @Test
+ public void nodeWithoutNamespaceHasMoreAugments() {
+ final var ex = assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("main:cont/cont1"));
+ assertThat(ex.getErrors().get(0).getErrorMessage(),
+ containsString("is added as augment from more than one module"));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java
new file mode 100644
index 0000000..65fa8e0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class RestGetOperationTest extends JerseyTest {
+
+ static class NodeData {
+ Object key;
+ Object data; // List for a CompositeNode, value Object for a SimpleNode
+
+ NodeData(final Object key, final Object data) {
+ this.key = key;
+ this.data = data;
+ }
+ }
+
+ private static EffectiveModelContext schemaContextYangsIetf;
+ private static EffectiveModelContext schemaContextTestModule;
+ private static EffectiveModelContext schemaContextModules;
+ private static EffectiveModelContext schemaContextBehindMountPoint;
+
+ private static NormalizedNode answerFromGet;
+
+ private BrokerFacade brokerFacade;
+ private RestconfImpl restconfImpl;
+ private ControllerContext controllerContext;
+ private DOMMountPoint mountInstance;
+
+ private static final String RESTCONF_NS = "urn:ietf:params:xml:ns:yang:ietf-restconf";
+
+ @BeforeClass
+ public static void init() throws Exception {
+ schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
+ schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module");
+ schemaContextModules = TestUtils.loadSchemaContext("/modules");
+ schemaContextBehindMountPoint = TestUtils.loadSchemaContext("/modules/modules-behind-mount-point");
+
+ answerFromGet = TestUtils.prepareNormalizedNodeWithIetfInterfacesInterfacesData();
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ mountInstance = mock(DOMMountPoint.class);
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContextYangsIetf, mountInstance);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl, new NormalizedNodeJsonBodyWriter(),
+ new NormalizedNodeXmlBodyWriter(), new XmlNormalizedNodeBodyReader(controllerContext),
+ new JsonNormalizedNodeBodyReader(controllerContext),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ private void setControllerContext(final EffectiveModelContext schemaContext) {
+ controllerContext.setSchemas(schemaContext);
+ }
+
+ /**
+ * Tests of status codes for "/operational/{identifier}".
+ */
+ @Test
+ public void getOperationalStatusCodes() throws Exception {
+ setControllerContext(schemaContextYangsIetf);
+ mockReadOperationalDataMethod();
+ String uri = "/operational/ietf-interfaces:interfaces/interface/eth0";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+
+ uri = "/operational/wrong-module:interfaces/interface/eth0";
+ assertEquals(400, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ /**
+ * Tests of status codes for "/config/{identifier}".
+ */
+ @Test
+ public void getConfigStatusCodes() throws Exception {
+ setControllerContext(schemaContextYangsIetf);
+ mockReadConfigurationDataMethod();
+ String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+
+ uri = "/config/wrong-module:interfaces/interface/eth0";
+ assertEquals(400, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ /**
+ * MountPoint test. URI represents mount point.
+ */
+ @Test
+ public void getDataWithUrlMountPoint() throws Exception {
+ when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+ isNull())).thenReturn(prepareCnDataForMountPointTest(false));
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextTestModule)));
+
+ String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/cont1";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+
+ uri = "/config/ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ /**
+ * MountPoint test. URI represents mount point.
+ * Slashes in URI behind mount point. lst1 element with key GigabitEthernet0%2F0%2F0%2F0 (GigabitEthernet0/0/0/0) is
+ * requested via GET HTTP operation. It is tested whether %2F character is replaced with simple / in
+ * InstanceIdentifier parameter in method
+ * {@link BrokerFacade#readConfigurationData(DOMMountPoint, YangInstanceIdentifier)} which is called in
+ * method {@link RestconfImpl#readConfigurationData}
+ */
+ @Test
+ public void getDataWithSlashesBehindMountPoint() throws Exception {
+ final YangInstanceIdentifier awaitedInstanceIdentifier = prepareInstanceIdentifierForList();
+ when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), eq(awaitedInstanceIdentifier),
+ isNull())).thenReturn(prepareCnDataForSlashesBehindMountPointTest());
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextTestModule)));
+
+ final String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/"
+ + "test-module:cont/lst1/GigabitEthernet0%2F0%2F0%2F0";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ private static YangInstanceIdentifier prepareInstanceIdentifierForList() throws Exception {
+ final List<PathArgument> parameters = new ArrayList<>();
+
+ final QName qNameCont = newTestModuleQName("cont");
+ final QName qNameList = newTestModuleQName("lst1");
+ final QName qNameKeyList = newTestModuleQName("lf11");
+
+ parameters.add(new NodeIdentifier(qNameCont));
+ parameters.add(new NodeIdentifier(qNameList));
+ parameters.add(NodeIdentifierWithPredicates.of(qNameList, qNameKeyList, "GigabitEthernet0/0/0/0"));
+ return YangInstanceIdentifier.create(parameters);
+ }
+
+ private static QName newTestModuleQName(final String localPart) throws Exception {
+ return QName.create("test:module", "2014-01-09", localPart);
+ }
+
+ @Test
+ public void getDataMountPointIntoHighestElement() throws Exception {
+ when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+ isNull())).thenReturn(prepareCnDataForMountPointTest(true));
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextTestModule)));
+
+ final String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ @Test
+ public void getDataWithIdentityrefInURL() throws Exception {
+ setControllerContext(schemaContextTestModule);
+
+ final QName moduleQN = newTestModuleQName("module");
+ final ImmutableMap<QName, Object> keyMap = ImmutableMap.of(
+ newTestModuleQName("type"), newTestModuleQName("test-identity"),
+ newTestModuleQName("name"), "foo");
+ final YangInstanceIdentifier iid = YangInstanceIdentifier.builder().node(newTestModuleQName("modules"))
+ .node(moduleQN).nodeWithKey(moduleQN, keyMap).build();
+ final NormalizedNode data = ImmutableMapNodeBuilder.create()
+ .withNodeIdentifier(new NodeIdentifier(moduleQN))
+ .withChild(ImmutableNodes.mapEntryBuilder()
+ .withNodeIdentifier(NodeIdentifierWithPredicates.of(moduleQN, keyMap))
+ .withChild(ImmutableNodes.leafNode(newTestModuleQName("type"), newTestModuleQName("test-identity")))
+ .withChild(ImmutableNodes.leafNode(newTestModuleQName("name"), "foo"))
+ .withChild(ImmutableNodes.leafNode(newTestModuleQName("data"), "bar")).build()).build();
+ when(brokerFacade.readConfigurationData(iid, null)).thenReturn(data);
+
+ final String uri = "/config/test-module:modules/module/test-module:test-identity/foo";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ // /modules
+ @Test
+ public void getModulesTest() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ final String uri = "/modules";
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ validateModulesResponseJson(response);
+
+ response = target(uri).request("application/yang.api+xml").get();
+ validateModulesResponseXml(response,schemaContextModules);
+ }
+
+ // /streams/
+ @Test
+ @Ignore // FIXME : find why it is fail by in gerrit build
+ public void getStreamsTest() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ final String uri = "/streams";
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ final String responseBody = response.readEntity(String.class);
+ assertEquals(200, response.getStatus());
+ assertNotNull(responseBody);
+ assertTrue(responseBody.contains("streams"));
+
+ response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ final Document responseXmlBody = response.readEntity(Document.class);
+ assertNotNull(responseXmlBody);
+ final Element rootNode = responseXmlBody.getDocumentElement();
+
+ assertEquals("streams", rootNode.getLocalName());
+ assertEquals(RESTCONF_NS, rootNode.getNamespaceURI());
+ }
+
+ // /modules/module
+ @Test
+ public void getModuleTest() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ final String uri = "/modules/module/module2/2014-01-02";
+
+ Response response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ final Document responseXml = response.readEntity(Document.class);
+
+ final QName qname = assertedModuleXmlToModuleQName(responseXml.getDocumentElement());
+ assertNotNull(qname);
+
+ assertEquals("module2", qname.getLocalName());
+ assertEquals("module:2", qname.getNamespace().toString());
+ assertEquals("2014-01-02", qname.getRevision().get().toString());
+
+ response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+ assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
+ .find());
+ final String[] split = responseBody.split("\"module\"");
+ assertEquals("\"module\" element is returned more then once", 2, split.length);
+
+ }
+
+ // /operations
+ @Ignore
+ @Test
+ public void getOperationsTest() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ final String uri = "/operations";
+
+ Response response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(500, response.getStatus());
+ final Document responseDoc = response.readEntity(Document.class);
+ validateOperationsResponseXml(responseDoc, schemaContextModules);
+
+ response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+ assertTrue("Json response for /operations dummy-rpc1-module1 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc1-module1", "module1").find());
+ assertTrue("Json response for /operations dummy-rpc2-module1 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc2-module1", "module1").find());
+ assertTrue("Json response for /operations dummy-rpc1-module2 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc1-module2", "module2").find());
+ assertTrue("Json response for /operations dummy-rpc2-module2 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc2-module2", "module2").find());
+ }
+
+ private static void validateOperationsResponseXml(final Document responseDoc, final SchemaContext schemaContext) {
+
+ final Element operationsElem = responseDoc.getDocumentElement();
+ assertEquals(RESTCONF_NS, operationsElem.getNamespaceURI());
+ assertEquals("operations", operationsElem.getLocalName());
+
+ final NodeList operationsList = operationsElem.getChildNodes();
+ final HashSet<String> foundOperations = new HashSet<>();
+
+ for (int i = 0; i < operationsList.getLength(); i++) {
+ final org.w3c.dom.Node operation = operationsList.item(i);
+ foundOperations.add(operation.getLocalName());
+ }
+
+ for (final RpcDefinition schemaOp : schemaContext.getOperations()) {
+ assertTrue(foundOperations.contains(schemaOp.getQName().getLocalName()));
+ }
+ }
+
+ // /operations/pathToMountPoint/yang-ext:mount
+ @Ignore
+ @Test
+ public void getOperationsBehindMountPointTest() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ mockMountPoint();
+
+ final String uri = "/operations/ietf-interfaces:interfaces/interface/0/yang-ext:mount/";
+
+ Response response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(500, response.getStatus());
+
+ final Document responseDoc = response.readEntity(Document.class);
+ validateOperationsResponseXml(responseDoc, schemaContextBehindMountPoint);
+
+ response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+ assertTrue("Json response for /operations/mount_point rpc-behind-module1 is incorrect",
+ validateOperationsResponseJson(responseBody, "rpc-behind-module1", "module1-behind-mount-point").find());
+ assertTrue("Json response for /operations/mount_point rpc-behind-module2 is incorrect",
+ validateOperationsResponseJson(responseBody, "rpc-behind-module2", "module2-behind-mount-point").find());
+
+ }
+
+ private static Matcher validateOperationsResponseJson(final String searchIn, final String rpcName,
+ final String moduleName) {
+ final StringBuilder regex = new StringBuilder();
+ regex.append(".*\"" + rpcName + "\"");
+ final Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+ return ptrn.matcher(searchIn);
+
+ }
+
+ // /restconf/modules/pathToMountPoint/yang-ext:mount
+ @Test
+ public void getModulesBehindMountPoint() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ mockMountPoint();
+
+ final String uri = "/modules/ietf-interfaces:interfaces/interface/0/yang-ext:mount/";
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+
+ assertTrue(
+ "module1-behind-mount-point in json wasn't found",
+ prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
+ responseBody).find());
+ assertTrue(
+ "module2-behind-mount-point in json wasn't found",
+ prepareJsonRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point",
+ responseBody).find());
+
+ response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ validateModulesResponseXml(response, schemaContextBehindMountPoint);
+
+ }
+
+ // /restconf/modules/module/pathToMountPoint/yang-ext:mount/moduleName/revision
+ @Test
+ public void getModuleBehindMountPoint() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ mockMountPoint();
+
+ final String uri = "/modules/module/ietf-interfaces:interfaces/interface/0/yang-ext:mount/"
+ + "module1-behind-mount-point/2014-02-03";
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+
+ assertTrue(
+ "module1-behind-mount-point in json wasn't found",
+ prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
+ responseBody).find());
+ final String[] split = responseBody.split("\"module\"");
+ assertEquals("\"module\" element is returned more then once", 2, split.length);
+
+ response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ final Document responseXml = response.readEntity(Document.class);
+
+ final QName module = assertedModuleXmlToModuleQName(responseXml.getDocumentElement());
+
+ assertEquals("module1-behind-mount-point", module.getLocalName());
+ assertEquals("2014-02-03", module.getRevision().get().toString());
+ assertEquals("module:1:behind:mount:point", module.getNamespace().toString());
+ }
+
+ private static void validateModulesResponseXml(final Response response, final SchemaContext schemaContext) {
+ assertEquals(200, response.getStatus());
+ final Document responseBody = response.readEntity(Document.class);
+ final NodeList moduleNodes = responseBody.getDocumentElement().getElementsByTagNameNS(RESTCONF_NS, "module");
+
+ assertTrue(moduleNodes.getLength() > 0);
+
+ final HashSet<QName> foundModules = new HashSet<>();
+
+ for (int i = 0; i < moduleNodes.getLength(); i++) {
+ final org.w3c.dom.Node module = moduleNodes.item(i);
+
+ final QName name = assertedModuleXmlToModuleQName(module);
+ foundModules.add(name);
+ }
+
+ assertAllModules(foundModules,schemaContext);
+ }
+
+ private static void assertAllModules(final Set<QName> foundModules, final SchemaContext schemaContext) {
+ for (final Module module : schemaContext.getModules()) {
+ final QName current = QName.create(module.getQNameModule(), module.getName());
+ assertTrue("Module not found in response.", foundModules.contains(current));
+ }
+
+ }
+
+ private static QName assertedModuleXmlToModuleQName(final org.w3c.dom.Node module) {
+ assertEquals("module", module.getLocalName());
+ assertEquals(RESTCONF_NS, module.getNamespaceURI());
+ String revision = null;
+ String namespace = null;
+ String name = null;
+
+
+ final NodeList childNodes = module.getChildNodes();
+
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ final org.w3c.dom.Node child = childNodes.item(i);
+ assertEquals(RESTCONF_NS, child.getNamespaceURI());
+
+ switch (child.getLocalName()) {
+ case "name":
+ assertNull("Name element appeared multiple times", name);
+ name = child.getTextContent().trim();
+ break;
+ case "revision":
+ assertNull("Revision element appeared multiple times", revision);
+ revision = child.getTextContent().trim();
+ break;
+ case "namespace":
+ assertNull("Namespace element appeared multiple times", namespace);
+ namespace = child.getTextContent().trim();
+ break;
+ default:
+ break;
+ }
+ }
+
+ assertNotNull("Revision was not part of xml",revision);
+ assertNotNull("Module namespace was not part of xml",namespace);
+ assertNotNull("Module identiffier was not part of xml",name);
+
+ return QName.create(namespace,revision,name);
+ }
+
+ private static void validateModulesResponseJson(final Response response) {
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+
+ assertTrue("Module1 in json wasn't found", prepareJsonRegex("module1", "2014-01-01", "module:1", responseBody)
+ .find());
+ assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
+ .find());
+ assertTrue("Module3 in json wasn't found", prepareJsonRegex("module3", "2014-01-03", "module:3", responseBody)
+ .find());
+ }
+
+ private static Matcher prepareJsonRegex(final String module, final String revision, final String namespace,
+ final String searchIn) {
+ final StringBuilder regex = new StringBuilder();
+ regex.append("^");
+
+ regex.append(".*\\{");
+ regex.append(".*\"name\"");
+ regex.append(".*:");
+ regex.append(".*\"" + module + "\",");
+
+ regex.append(".*\"revision\"");
+ regex.append(".*:");
+ regex.append(".*\"" + revision + "\",");
+
+ regex.append(".*\"namespace\"");
+ regex.append(".*:");
+ regex.append(".*\"" + namespace + "\"");
+
+ regex.append(".*\\}");
+
+ regex.append(".*");
+ regex.append("$");
+ final Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+ return ptrn.matcher(searchIn);
+
+ }
+
+
+ private int get(final String uri, final String mediaType) {
+ return target(uri).request(mediaType).get().getStatus();
+ }
+
+ /**
+ * Container structure.
+ *
+ * <p>
+ * container cont {
+ * container cont1 {
+ * leaf lf11 {
+ * type string;
+ * }
+ */
+ private static NormalizedNode prepareCnDataForMountPointTest(final boolean wrapToCont) throws Exception {
+ final String testModuleDate = "2014-01-09";
+ final ContainerNode contChild = Builders
+ .containerBuilder()
+ .withNodeIdentifier(TestUtils.getNodeIdentifier("cont1", "test:module", testModuleDate))
+ .withChild(
+ Builders.leafBuilder()
+ .withNodeIdentifier(TestUtils.getNodeIdentifier("lf11", "test:module", testModuleDate))
+ .withValue("lf11 value").build()).build();
+
+ if (wrapToCont) {
+ return Builders.containerBuilder()
+ .withNodeIdentifier(TestUtils.getNodeIdentifier("cont", "test:module", testModuleDate))
+ .withChild(contChild).build();
+ }
+ return contChild;
+
+ }
+
+ private void mockReadOperationalDataMethod() {
+ when(brokerFacade.readOperationalData(any(YangInstanceIdentifier.class))).thenReturn(answerFromGet);
+ }
+
+ private void mockReadConfigurationDataMethod() {
+ when(brokerFacade.readConfigurationData(any(YangInstanceIdentifier.class), isNull()))
+ .thenReturn(answerFromGet);
+ }
+
+ private static NormalizedNode prepareCnDataForSlashesBehindMountPointTest() throws Exception {
+ return ImmutableMapEntryNodeBuilder.create()
+ .withNodeIdentifier(
+ TestUtils.getNodeIdentifierPredicate("lst1", "test:module", "2014-01-09", "lf11",
+ "GigabitEthernet0/0/0/0"))
+ .withChild(
+ ImmutableLeafNodeBuilder.create()
+ .withNodeIdentifier(TestUtils.getNodeIdentifier("lf11", "test:module", "2014-01-09"))
+ .withValue("GigabitEthernet0/0/0/0").build()).build();
+
+ }
+
+ /**
+ * If includeWhiteChars URI parameter is set to false then no white characters can be included in returned output.
+ */
+ @Test
+ public void getDataWithUriIncludeWhiteCharsParameterTest() throws Exception {
+ getDataWithUriIncludeWhiteCharsParameter("config");
+ getDataWithUriIncludeWhiteCharsParameter("operational");
+ }
+
+ private void getDataWithUriIncludeWhiteCharsParameter(final String target) throws Exception {
+ mockReadConfigurationDataMethod();
+ mockReadOperationalDataMethod();
+ final String uri = "/" + target + "/ietf-interfaces:interfaces/interface/eth0";
+ Response response = target(uri).queryParam("prettyPrint", "false").request("application/xml").get();
+ final String xmlData = response.readEntity(String.class);
+
+ Pattern pattern = Pattern.compile(".*(>\\s+|\\s+<).*", Pattern.DOTALL);
+ Matcher matcher = pattern.matcher(xmlData);
+ // XML element can't surrounded with white character (e.g "> " or
+ // " <")
+ assertFalse(matcher.matches());
+
+ response = target(uri).queryParam("prettyPrint", "false").request("application/json").get();
+ final String jsonData = response.readEntity(String.class);
+ pattern = Pattern.compile(".*(\\}\\s+|\\s+\\{|\\]\\s+|\\s+\\[|\\s+:|:\\s+).*", Pattern.DOTALL);
+ matcher = pattern.matcher(jsonData);
+ // JSON element can't surrounded with white character (e.g "} ", " {",
+ // "] ", " [", " :" or ": ")
+ assertFalse(matcher.matches());
+ }
+
+ /**
+ * Tests behavior when invalid value of depth URI parameter.
+ */
+ @Test
+ @Ignore
+ public void getDataWithInvalidDepthParameterTest() {
+ setControllerContext(schemaContextModules);
+
+ final MultivaluedMap<String, String> paramMap = new MultivaluedHashMap<>();
+ paramMap.putSingle("depth", "1o");
+ final UriInfo mockInfo = mock(UriInfo.class);
+ when(mockInfo.getQueryParameters(false)).thenAnswer(invocation -> paramMap);
+
+ getDataWithInvalidDepthParameterTest(mockInfo);
+
+ paramMap.putSingle("depth", "0");
+ getDataWithInvalidDepthParameterTest(mockInfo);
+
+ paramMap.putSingle("depth", "-1");
+ getDataWithInvalidDepthParameterTest(mockInfo);
+ }
+
+ private void getDataWithInvalidDepthParameterTest(final UriInfo uriInfo) {
+ try {
+ final QName qNameDepth1Cont = QName.create("urn:nested:module", "2014-06-3", "depth1-cont");
+ final YangInstanceIdentifier ii = YangInstanceIdentifier.builder().node(qNameDepth1Cont).build();
+ final NormalizedNode value =
+ Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(qNameDepth1Cont)).build();
+ when(brokerFacade.readConfigurationData(eq(ii))).thenReturn(value);
+ restconfImpl.readConfigurationData("nested-module:depth1-cont", uriInfo);
+ fail("Expected RestconfDocumentedException");
+ } catch (final RestconfDocumentedException e) {
+ assertTrue("Unexpected error message: " + e.getErrors().get(0).getErrorMessage(), e.getErrors().get(0)
+ .getErrorMessage().contains("depth"));
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private void verifyXMLResponse(final Response response, final NodeData nodeData) {
+ final Document doc = response.readEntity(Document.class);
+ assertNotNull("Could not parse XML document", doc);
+
+ verifyContainerElement(doc.getDocumentElement(), nodeData);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void verifyContainerElement(final Element element, final NodeData nodeData) {
+
+ assertEquals("Element local name", nodeData.key, element.getLocalName());
+
+ final NodeList childNodes = element.getChildNodes();
+ if (nodeData.data == null) { // empty container
+ assertTrue(
+ "Expected no child elements for \"" + element.getLocalName() + "\"", childNodes.getLength() == 0);
+ return;
+ }
+
+ final Map<String, NodeData> expChildMap = new HashMap<>();
+ for (final NodeData expChild : (List<NodeData>) nodeData.data) {
+ expChildMap.put(expChild.key.toString(), expChild);
+ }
+
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ final org.w3c.dom.Node actualChild = childNodes.item(i);
+ if (!(actualChild instanceof Element)) {
+ continue;
+ }
+
+ final Element actualElement = (Element) actualChild;
+ final NodeData expChild = expChildMap.remove(actualElement.getLocalName());
+ assertNotNull(
+ "Unexpected child element for parent \"" + element.getLocalName() + "\": "
+ + actualElement.getLocalName(), expChild);
+
+ if (expChild.data == null || expChild.data instanceof List) {
+ verifyContainerElement(actualElement, expChild);
+ } else {
+ assertEquals("Text content for element: " + actualElement.getLocalName(), expChild.data,
+ actualElement.getTextContent());
+ }
+ }
+
+ if (!expChildMap.isEmpty()) {
+ fail("Missing elements for parent \"" + element.getLocalName() + "\": " + expChildMap.keySet());
+ }
+ }
+
+ private void mockMountPoint() {
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextBehindMountPoint)));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java
new file mode 100644
index 0000000..bdc9679
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+public final class RestOperationUtils {
+
+ public static final String JSON = "+json";
+ public static final String XML = "+xml";
+
+ private RestOperationUtils() {
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java
new file mode 100644
index 0000000..3aa6a9c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.XML;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.FluentFuture;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.util.Optional;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class RestPostOperationTest extends JerseyTest {
+
+ private static String xmlBlockData;
+ private static String xmlData3;
+ private static String xmlData4;
+
+ private static EffectiveModelContext schemaContextYangsIetf;
+ private static EffectiveModelContext schemaContextTestModule;
+ private static EffectiveModelContext schemaContext;
+
+ private BrokerFacade brokerFacade;
+ private RestconfImpl restconfImpl;
+ private ControllerContext controllerContext;
+ private DOMMountPoint mountInstance;
+
+ @BeforeClass
+ public static void init() throws URISyntaxException, IOException {
+ schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
+ schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module");
+ schemaContext = TestUtils.loadSchemaContext("/test-config-data/yang1");
+ loadData();
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ mountInstance = mock(DOMMountPoint.class);
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext, mountInstance);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl,
+ new XmlNormalizedNodeBodyReader(controllerContext), new NormalizedNodeXmlBodyWriter(),
+ new JsonNormalizedNodeBodyReader(controllerContext), new NormalizedNodeJsonBodyWriter(),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ private void setSchemaControllerContext(final EffectiveModelContext schema) {
+ controllerContext.setSchemas(schema);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ @Ignore /// xmlData* need netconf-yang
+ public void postDataViaUrlMountPoint() throws UnsupportedEncodingException {
+ setSchemaControllerContext(schemaContextYangsIetf);
+ when(brokerFacade.commitConfigurationDataPost(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+ any(NormalizedNode.class), null, null)).thenReturn(mock(FluentFuture.class));
+
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextTestModule)));
+
+ String uri = "/config/ietf-interfaces:interfaces/interface/0/";
+ assertEquals(204, post(uri, Draft02.MediaTypes.DATA + XML, xmlData4));
+ uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont";
+ assertEquals(204, post(uri, Draft02.MediaTypes.DATA + XML, xmlData3));
+
+ assertEquals(400, post(uri, MediaType.APPLICATION_JSON, ""));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ @Ignore //jenkins has problem with JerseyTest
+ // - we expecting problems with singletons ControllerContext as schemaContext holder
+ public void createConfigurationDataTest() throws UnsupportedEncodingException, ParseException {
+ when(brokerFacade.commitConfigurationDataPost((EffectiveModelContext) null, any(YangInstanceIdentifier.class),
+ any(NormalizedNode.class), null, null))
+ .thenReturn(mock(FluentFuture.class));
+
+ final ArgumentCaptor<YangInstanceIdentifier> instanceIdCaptor =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ final ArgumentCaptor<NormalizedNode> compNodeCaptor = ArgumentCaptor.forClass(NormalizedNode.class);
+
+
+ // FIXME : identify who is set the schemaContext
+// final String URI_1 = "/config";
+// assertEquals(204, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface));
+// verify(brokerFacade).commitConfigurationDataPost(instanceIdCaptor.capture(), compNodeCaptor.capture());
+ final String identifier = "[(urn:ietf:params:xml:ns:yang:test-interface?revision=2014-07-01)interfaces]";
+// assertEquals(identifier, ImmutableList.copyOf(instanceIdCaptor.getValue().getPathArguments()).toString());
+
+ final String URI_2 = "/config/test-interface:interfaces";
+ assertEquals(204, post(URI_2, Draft02.MediaTypes.DATA + XML, xmlBlockData));
+ // FIXME : NEVER test a nr. of call some service in complex test suite
+// verify(brokerFacade, times(2))
+ verify(brokerFacade, times(1))
+ .commitConfigurationDataPost((EffectiveModelContext) null, instanceIdCaptor.capture(),
+ compNodeCaptor.capture(), null, null);
+// identifier = "[(urn:ietf:params:xml:ns:yang:test-interface?revision=2014-07-01)interfaces," +
+// "(urn:ietf:params:xml:ns:yang:test-interface?revision=2014-07-01)block]";
+ assertEquals(identifier, ImmutableList.copyOf(instanceIdCaptor.getValue().getPathArguments()).toString());
+ }
+
+ @Test
+ public void createConfigurationDataNullTest() throws UnsupportedEncodingException {
+ doReturn(CommitInfo.emptyFluentFuture()).when(brokerFacade).commitConfigurationDataPost(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class), isNull(),
+ isNull());
+
+ //FIXME : find who is set schemaContext
+// final String URI_1 = "/config";
+// assertEquals(204, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface));
+
+ final String URI_2 = "/config/test-interface:interfaces";
+ assertEquals(204, post(URI_2, Draft02.MediaTypes.DATA + XML, xmlBlockData));
+ }
+
+ private int post(final String uri, final String mediaType, final String data) {
+ return target(uri).request(mediaType).post(Entity.entity(data, mediaType)).getStatus();
+ }
+
+ private static void loadData() throws IOException, URISyntaxException {
+ final String xmlPathBlockData =
+ RestconfImplTest.class.getResource("/test-config-data/xml/block-data.xml").getPath();
+ xmlBlockData = TestUtils.loadTextFile(xmlPathBlockData);
+ final String data3Input = RestconfImplTest.class.getResource("/full-versions/test-data2/data3.xml").getPath();
+ xmlData3 = TestUtils.loadTextFile(data3Input);
+ final String data4Input = RestconfImplTest.class.getResource("/full-versions/test-data2/data7.xml").getPath();
+ xmlData4 = TestUtils.loadTextFile(data4Input);
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java
new file mode 100644
index 0000000..9cd03d8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.io.FileNotFoundException;
+import java.util.HashSet;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RestPutConfigTest {
+
+ private static EffectiveModelContext schemaContext;
+ private RestconfImpl restconfService;
+ private ControllerContext controllerCx;
+
+ @Mock
+ private BrokerFacade brokerFacade;
+
+ @BeforeClass
+ public static void staticInit() throws FileNotFoundException {
+ schemaContext = TestRestconfUtils.loadSchemaContext("/test-config-data/yang1/", null);
+ }
+
+ @Before
+ public void init() {
+ controllerCx = TestRestconfUtils.newControllerContext(schemaContext);
+ restconfService = RestconfImpl.newInstance(brokerFacade, controllerCx);
+ }
+
+ @Test
+ public void testPutConfigData() {
+ final String identifier = "test-interface:interfaces/interface/key";
+ final InstanceIdentifierContext iiCx = controllerCx.toInstanceIdentifier(identifier);
+ final MapEntryNode data = Mockito.mock(MapEntryNode.class);
+ final QName qName = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "interface");
+ final QName qNameKey = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "name");
+ final NodeIdentifierWithPredicates identWithPredicates =
+ NodeIdentifierWithPredicates.of(qName, qNameKey, "key");
+ Mockito.when(data.getIdentifier()).thenReturn(identWithPredicates);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iiCx, data);
+
+ mockingBrokerPut(iiCx.getInstanceIdentifier(), data);
+
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ final MultivaluedMap<String, String> value = Mockito.mock(MultivaluedMap.class);
+ Mockito.when(value.entrySet()).thenReturn(new HashSet<>());
+ Mockito.when(uriInfo.getQueryParameters()).thenReturn(value);
+ restconfService.updateConfigurationData(identifier, payload, uriInfo);
+ }
+
+ @Test
+ public void testPutConfigDataCheckOnlyLastElement() {
+ final String identifier = "test-interface:interfaces/interface/key/sub-interface/subkey";
+ final InstanceIdentifierContext iiCx = controllerCx.toInstanceIdentifier(identifier);
+ final MapEntryNode data = Mockito.mock(MapEntryNode.class);
+ final QName qName = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "sub-interface");
+ final QName qNameSubKey = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "sub-name");
+ final NodeIdentifierWithPredicates identWithPredicates =
+ NodeIdentifierWithPredicates.of(qName, qNameSubKey, "subkey");
+ Mockito.when(data.getIdentifier()).thenReturn(identWithPredicates);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iiCx, data);
+
+ mockingBrokerPut(iiCx.getInstanceIdentifier(), data);
+
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ final MultivaluedMap<String, String> value = Mockito.mock(MultivaluedMap.class);
+ Mockito.when(value.entrySet()).thenReturn(new HashSet<>());
+ Mockito.when(uriInfo.getQueryParameters()).thenReturn(value);
+ restconfService.updateConfigurationData(identifier, payload, uriInfo);
+ }
+
+ @Test(expected = RestconfDocumentedException.class)
+ public void testPutConfigDataMissingUriKey() {
+ final String identifier = "test-interface:interfaces/interface";
+ controllerCx.toInstanceIdentifier(identifier);
+ }
+
+ @Test(expected = RestconfDocumentedException.class)
+ public void testPutConfigDataDiferentKey() {
+ final String identifier = "test-interface:interfaces/interface/key";
+ final InstanceIdentifierContext iiCx = controllerCx.toInstanceIdentifier(identifier);
+ final MapEntryNode data = Mockito.mock(MapEntryNode.class);
+ final QName qName = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "interface");
+ final QName qNameKey = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "name");
+ final NodeIdentifierWithPredicates identWithPredicates =
+ NodeIdentifierWithPredicates.of(qName, qNameKey, "notSameKey");
+ Mockito.when(data.getIdentifier()).thenReturn(identWithPredicates);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iiCx, data);
+
+ mockingBrokerPut(iiCx.getInstanceIdentifier(), data);
+
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ final MultivaluedMap<String, String> value = Mockito.mock(MultivaluedMap.class);
+ Mockito.when(value.entrySet()).thenReturn(new HashSet<>());
+ Mockito.when(uriInfo.getQueryParameters()).thenReturn(value);
+ restconfService.updateConfigurationData(identifier, payload, uriInfo);
+ }
+
+ private void mockingBrokerPut(final YangInstanceIdentifier yii, final NormalizedNode data) {
+ final PutResult result = Mockito.mock(PutResult.class);
+ Mockito.when(brokerFacade.commitConfigurationDataPut(schemaContext, yii, data, null, null))
+ .thenReturn(result);
+ Mockito.doReturn(CommitInfo.emptyFluentFuture()).when(result).getFutureOfPutData();
+ Mockito.when(result.getStatus()).thenReturn(Status.OK);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java
new file mode 100644
index 0000000..8c04e50
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.util.Optional;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.OptimisticLockFailedException;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+//TODO UNSTABLE TESTS - FIX ME
+@Ignore
+public class RestPutOperationTest extends JerseyTest {
+
+ private static String xmlData;
+ private static String xmlData2;
+ private static String xmlData3;
+
+ private static EffectiveModelContext schemaContextYangsIetf;
+ private static EffectiveModelContext schemaContextTestModule;
+
+ private BrokerFacade brokerFacade;
+ private RestconfImpl restconfImpl;
+ private DOMMountPoint mountInstance;
+
+ @BeforeClass
+ public static void init() throws IOException, ReactorException {
+ schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
+ schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module");
+ loadData();
+ }
+
+ private static void loadData() throws IOException {
+ final InputStream xmlStream =
+ RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+ xmlData = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream));
+ final InputStream xmlStream2 =
+ RestconfImplTest.class.getResourceAsStream("/full-versions/test-data2/data2.xml");
+ xmlData2 = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream2));
+ final InputStream xmlStream3 =
+ RestconfImplTest.class.getResourceAsStream("/full-versions/test-data2/data7.xml");
+ xmlData3 = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream3));
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ mountInstance = mock(DOMMountPoint.class);
+ final ControllerContext controllerContext =
+ TestRestconfUtils.newControllerContext(schemaContextYangsIetf, mountInstance);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl,
+ new XmlNormalizedNodeBodyReader(controllerContext), new NormalizedNodeXmlBodyWriter(),
+ new JsonNormalizedNodeBodyReader(controllerContext), new NormalizedNodeJsonBodyWriter(),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ /**
+ * Tests of status codes for "/config/{identifier}".
+ */
+ @Test
+ public void putConfigStatusCodes() throws UnsupportedEncodingException {
+ final String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
+ mockCommitConfigurationDataPutMethod(true);
+ assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
+
+ mockCommitConfigurationDataPutMethod(false);
+ assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
+
+ assertEquals(400, put(uri, MediaType.APPLICATION_JSON, ""));
+ }
+
+ @Test
+ public void putConfigStatusCodesEmptyBody() throws UnsupportedEncodingException {
+ final String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
+ @SuppressWarnings("unused")
+ final Response resp = target(uri).request(MediaType.APPLICATION_JSON).put(
+ Entity.entity("", MediaType.APPLICATION_JSON));
+ assertEquals(400, put(uri, MediaType.APPLICATION_JSON, ""));
+ }
+
+ @Test
+ public void testRpcResultCommitedToStatusCodesWithMountPoint() throws UnsupportedEncodingException,
+ FileNotFoundException, URISyntaxException {
+ final PutResult result = mock(PutResult.class);
+ when(brokerFacade.commitMountPointDataPut(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+ any(NormalizedNode.class), null, null)).thenReturn(result);
+ doReturn(CommitInfo.emptyFluentFuture()).when(result).getFutureOfPutData();
+ when(result.getStatus()).thenReturn(Status.OK);
+
+ mockMountPoint();
+
+ String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont";
+ assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData2));
+
+ uri = "/config/ietf-interfaces:interfaces/yang-ext:mount/test-module:cont";
+ assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData2));
+ }
+
+ @Test
+ public void putDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException {
+ final PutResult result = mock(PutResult.class);
+ doReturn(result).when(brokerFacade).commitMountPointDataPut(any(DOMMountPoint.class),
+ any(YangInstanceIdentifier.class), any(NormalizedNode.class), null, null);
+ doReturn(CommitInfo.emptyFluentFuture()).when(result).getFutureOfPutData();
+ when(result.getStatus()).thenReturn(Status.OK);
+
+ mockMountPoint();
+
+ final String uri = "/config/ietf-interfaces:interfaces/yang-ext:mount";
+ assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData3));
+ }
+
+ @Test
+ public void putWithOptimisticLockFailedException() throws UnsupportedEncodingException {
+
+ final String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
+
+ doThrow(OptimisticLockFailedException.class).when(brokerFacade).commitConfigurationDataPut(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class), null,
+ null);
+
+ assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
+
+ doThrow(OptimisticLockFailedException.class).doReturn(mock(PutResult.class)).when(brokerFacade)
+ .commitConfigurationDataPut(any(EffectiveModelContext.class), any(YangInstanceIdentifier.class),
+ any(NormalizedNode.class), null, null);
+
+ assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
+ }
+
+ @Test
+ public void putWithTransactionCommitFailedException() throws UnsupportedEncodingException {
+
+ final String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
+
+ doThrow(TransactionCommitFailedException.class)
+ .when(brokerFacade).commitConfigurationDataPut(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class),
+ null, null);
+
+ assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
+ }
+
+ private int put(final String uri, final String mediaType, final String data) throws UnsupportedEncodingException {
+ return target(uri).request(mediaType).put(Entity.entity(data, mediaType)).getStatus();
+ }
+
+ private void mockMountPoint() {
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextTestModule)));
+ }
+
+ private void mockCommitConfigurationDataPutMethod(final boolean noErrors) {
+ final PutResult putResMock = mock(PutResult.class);
+ if (noErrors) {
+ doReturn(putResMock).when(brokerFacade).commitConfigurationDataPut(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class),
+ null, null);
+ } else {
+ doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataPut(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class),
+ null, null);
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java
new file mode 100644
index 0000000..f4ddb35
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java
@@ -0,0 +1,831 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.Iterators;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathFactory;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * Unit tests for RestconfDocumentedExceptionMapper.
+ *
+ * @author Thomas Pantelis
+ */
+public class RestconfDocumentedExceptionMapperTest extends JerseyTest {
+
+ interface ErrorInfoVerifier {
+ void verifyXML(Node errorInfoNode);
+
+ void verifyJson(JsonElement errorInfoElement);
+ }
+
+ static class SimpleErrorInfoVerifier implements ErrorInfoVerifier {
+
+ String expTextContent;
+
+ SimpleErrorInfoVerifier(final String expErrorInfo) {
+ expTextContent = expErrorInfo;
+ }
+
+ void verifyContent(final String actualContent) {
+ assertNotNull("Actual \"error-info\" text content is null", actualContent);
+ assertTrue("", actualContent.contains(expTextContent));
+ }
+
+ @Override
+ public void verifyXML(final Node errorInfoNode) {
+ verifyContent(errorInfoNode.getTextContent());
+ }
+
+ @Override
+ public void verifyJson(final JsonElement errorInfoElement) {
+ verifyContent(errorInfoElement.getAsString());
+ }
+ }
+
+ private static final Logger LOG = LoggerFactory.getLogger(RestconfDocumentedExceptionMapperTest.class);
+ private static final String IETF_RESTCONF = "ietf-restconf";
+ static RestconfService mockRestConf = mock(RestconfService.class);
+
+ static XPath XPATH = XPathFactory.newInstance().newXPath();
+ static XPathExpression ERROR_LIST;
+ static XPathExpression ERROR_TYPE;
+ static XPathExpression ERROR_TAG;
+ static XPathExpression ERROR_MESSAGE;
+ static XPathExpression ERROR_APP_TAG;
+ static XPathExpression ERROR_INFO;
+
+ private static EffectiveModelContext schemaContext;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ schemaContext = TestUtils.loadSchemaContext("/modules");
+
+ final NamespaceContext nsContext = new NamespaceContext() {
+ @Override
+ public Iterator<String> getPrefixes(final String namespaceURI) {
+ return Iterators.singletonIterator(IETF_RESTCONF);
+ }
+
+ @Override
+ public String getPrefix(final String namespaceURI) {
+ return null;
+ }
+
+ @Override
+ public String getNamespaceURI(final String prefix) {
+ return IETF_RESTCONF.equals(prefix) ? Draft02.RestConfModule.NAMESPACE : null;
+ }
+ };
+
+ XPATH.setNamespaceContext(nsContext);
+ ERROR_LIST = XPATH.compile("ietf-restconf:errors/ietf-restconf:error");
+ ERROR_TYPE = XPATH.compile("ietf-restconf:error-type");
+ ERROR_TAG = XPATH.compile("ietf-restconf:error-tag");
+ ERROR_MESSAGE = XPATH.compile("ietf-restconf:error-message");
+ ERROR_APP_TAG = XPATH.compile("ietf-restconf:error-app-tag");
+ ERROR_INFO = XPATH.compile("ietf-restconf:error-info");
+ }
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ reset(mockRestConf);
+ super.setUp();
+ }
+
+ @Override
+ protected Application configure() {
+ ResourceConfig resourceConfig = new ResourceConfig();
+ ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ resourceConfig = resourceConfig.registerInstances(mockRestConf,
+ new XmlNormalizedNodeBodyReader(controllerContext), new JsonNormalizedNodeBodyReader(controllerContext),
+ new NormalizedNodeJsonBodyWriter(), new NormalizedNodeXmlBodyWriter(),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ void stageMockEx(final RestconfDocumentedException ex) {
+ reset(mockRestConf);
+ when(mockRestConf.readOperationalData(any(String.class), any(UriInfo.class))).thenThrow(ex);
+ }
+
+ void testJsonResponse(final RestconfDocumentedException ex, final Status expStatus, final ErrorType expErrorType,
+ final ErrorTag expErrorTag, final String expErrorMessage, final String expErrorAppTag,
+ final ErrorInfoVerifier errorInfoVerifier) throws Exception {
+
+ stageMockEx(ex);
+
+ final Response resp = target("/operational/foo").request(MediaType.APPLICATION_JSON).get();
+
+ final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_JSON, expStatus);
+
+ verifyJsonResponseBody(stream, expErrorType, expErrorTag, expErrorMessage, expErrorAppTag, errorInfoVerifier);
+ }
+
+ @Test
+ public void testToJsonResponseWithMessageOnly() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error"), Status.INTERNAL_SERVER_ERROR,
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null);
+
+
+ // To test verification code
+ // String json =
+ // "{ errors: {" +
+ // " error: [{" +
+ // " error-tag : \"operation-failed\"" +
+ // " ,error-type : \"application\"" +
+ // " ,error-message : \"An error occurred\"" +
+ // " ,error-info : {" +
+ // " session-id: \"123\"" +
+ // " ,address: \"1.2.3.4\"" +
+ // " }" +
+ // " }]" +
+ // " }" +
+ // "}";
+ //
+ // verifyJsonResponseBody( new java.io.StringBufferInputStream(json ),
+ // ErrorType.APPLICATION,
+ // ErrorTag.OPERATION_FAILED, "An error occurred", null,
+ // com.google.common.collect.ImmutableMap.of( "session-id", "123",
+ // "address", "1.2.3.4" ) );
+ }
+
+ @Test
+ public void testToJsonResponseWithInUseErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.IN_USE),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.IN_USE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithInvalidValueErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.RPC, ErrorTag.INVALID_VALUE),
+ Status.BAD_REQUEST, ErrorType.RPC, ErrorTag.INVALID_VALUE, "mock error", null, null);
+
+ }
+
+ @Test
+ public void testToJsonResponseWithTooBigErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.TRANSPORT, ErrorTag.TOO_BIG),
+ Status.REQUEST_ENTITY_TOO_LARGE, ErrorType.TRANSPORT, ErrorTag.TOO_BIG, "mock error", null, null);
+
+ }
+
+ @Test
+ public void testToJsonResponseWithMissingAttributeErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithBadAttributeErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithUnknownAttributeErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithBadElementErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithUnknownElementErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithUnknownNamespaceErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithMalformedMessageErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithAccessDeniedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.ACCESS_DENIED),
+ Status.FORBIDDEN, ErrorType.PROTOCOL, ErrorTag.ACCESS_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithLockDeniedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.LOCK_DENIED),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.LOCK_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithResourceDeniedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.RESOURCE_DENIED),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.RESOURCE_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithRollbackFailedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.ROLLBACK_FAILED),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.ROLLBACK_FAILED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithDataExistsErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithDataMissingErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithOperationNotSupportedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED), Status.NOT_IMPLEMENTED, ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithOperationFailedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.OPERATION_FAILED),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.OPERATION_FAILED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithPartialOperationErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.PARTIAL_OPERATION),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.PARTIAL_OPERATION, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithErrorAppTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag")), Status.BAD_REQUEST, ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", null);
+ }
+
+ @Test
+ @Ignore // FIXME : find why it return "error-type" RPC no expected APPLICATION
+ public void testToJsonResponseWithMultipleErrors() throws Exception {
+
+ final List<RestconfError> errorList = Arrays.asList(
+ new RestconfError(ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, "mock error1"),
+ new RestconfError(ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, "mock error2"));
+ stageMockEx(new RestconfDocumentedException("mock", null, errorList));
+
+ final Response resp = target("/operational/foo").request(MediaType.APPLICATION_JSON).get();
+
+ final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_JSON, Status.CONFLICT);
+
+ final JsonArray arrayElement = parseJsonErrorArrayElement(stream);
+
+ assertEquals("\"error\" Json array element length", 2, arrayElement.size());
+
+ verifyJsonErrorNode(
+ arrayElement.get(0), ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, "mock error1", null, null);
+
+ verifyJsonErrorNode(arrayElement.get(1), ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, "mock error2", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithErrorInfo() throws Exception {
+
+ final String errorInfo = "<address>1.2.3.4</address> <session-id>123</session-id>";
+ testJsonResponse(new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", errorInfo)), Status.BAD_REQUEST,
+ ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag",
+ new SimpleErrorInfoVerifier(errorInfo));
+ }
+
+ @Test
+ public void testToJsonResponseWithExceptionCause() throws Exception {
+
+ final Exception cause = new Exception("mock exception cause");
+ testJsonResponse(new RestconfDocumentedException("mock error", cause), Status.INTERNAL_SERVER_ERROR,
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null,
+ new SimpleErrorInfoVerifier(cause.getMessage()));
+ }
+
+ void testXMLResponse(final RestconfDocumentedException ex, final Status expStatus, final ErrorType expErrorType,
+ final ErrorTag expErrorTag, final String expErrorMessage, final String expErrorAppTag,
+ final ErrorInfoVerifier errorInfoVerifier) throws Exception {
+ stageMockEx(ex);
+
+ final Response resp = target("/operational/foo").request(MediaType.APPLICATION_XML).get();
+
+ final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_XML, expStatus);
+
+ verifyXMLResponseBody(stream, expErrorType, expErrorTag, expErrorMessage, expErrorAppTag, errorInfoVerifier);
+ }
+
+ @Test
+ public void testToXMLResponseWithMessageOnly() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error"), Status.INTERNAL_SERVER_ERROR,
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null);
+
+ // To test verification code
+ // String xml =
+ // "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">"+
+ // " <error>" +
+ // " <error-type>application</error-type>"+
+ // " <error-tag>operation-failed</error-tag>"+
+ // " <error-message>An error occurred</error-message>"+
+ // " <error-info>" +
+ // " <session-id>123</session-id>" +
+ // " <address>1.2.3.4</address>" +
+ // " </error-info>" +
+ // " </error>" +
+ // "</errors>";
+ //
+ // verifyXMLResponseBody( new java.io.StringBufferInputStream(xml),
+ // ErrorType.APPLICATION,
+ // ErrorTag.OPERATION_FAILED, "An error occurred", null,
+ // com.google.common.collect.ImmutableMap.of( "session-id", "123",
+ // "address", "1.2.3.4" ) );
+ }
+
+ @Test
+ public void testToXMLResponseWithInUseErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.IN_USE),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.IN_USE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithInvalidValueErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.RPC, ErrorTag.INVALID_VALUE),
+ Status.BAD_REQUEST, ErrorType.RPC, ErrorTag.INVALID_VALUE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithTooBigErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.TRANSPORT, ErrorTag.TOO_BIG),
+ Status.REQUEST_ENTITY_TOO_LARGE, ErrorType.TRANSPORT, ErrorTag.TOO_BIG, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithMissingAttributeErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithBadAttributeErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithUnknownAttributeErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithBadElementErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithUnknownElementErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithUnknownNamespaceErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithMalformedMessageErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithAccessDeniedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.ACCESS_DENIED),
+ Status.FORBIDDEN, ErrorType.PROTOCOL, ErrorTag.ACCESS_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithLockDeniedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.LOCK_DENIED),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.LOCK_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithResourceDeniedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.RESOURCE_DENIED),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.RESOURCE_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithRollbackFailedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.ROLLBACK_FAILED),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.ROLLBACK_FAILED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithDataExistsErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithDataMissingErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithOperationNotSupportedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED), Status.NOT_IMPLEMENTED, ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithOperationFailedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.OPERATION_FAILED),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.OPERATION_FAILED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithPartialOperationErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.PARTIAL_OPERATION),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.PARTIAL_OPERATION, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithErrorAppTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag")), Status.BAD_REQUEST, ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", null);
+ }
+
+ @Test
+ public void testToXMLResponseWithErrorInfo() throws Exception {
+
+ final String errorInfo = "<address>1.2.3.4</address> <session-id>123</session-id>";
+ testXMLResponse(new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", errorInfo)), Status.BAD_REQUEST,
+ ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag",
+ new SimpleErrorInfoVerifier(errorInfo));
+ }
+
+ @Test
+ public void testToXMLResponseWithExceptionCause() throws Exception {
+
+ final Exception cause = new Exception("mock exception cause");
+ testXMLResponse(new RestconfDocumentedException("mock error", cause), Status.INTERNAL_SERVER_ERROR,
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null,
+ new SimpleErrorInfoVerifier(cause.getMessage()));
+ }
+
+ @Test
+ @Ignore // FIXME : find why it return error-type as RPC no APPLICATION
+ public void testToXMLResponseWithMultipleErrors() throws Exception {
+
+ final List<RestconfError> errorList = Arrays.asList(
+ new RestconfError(ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, "mock error1"),
+ new RestconfError(ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, "mock error2"));
+ stageMockEx(new RestconfDocumentedException("mock", null, errorList));
+
+ final Response resp = target("/operational/foo").request(MediaType.APPLICATION_XML).get();
+
+ final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_XML, Status.CONFLICT);
+
+ final Document doc = parseXMLDocument(stream);
+
+ final NodeList children = getXMLErrorList(doc, 2);
+
+ verifyXMLErrorNode(children.item(0), ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, "mock error1", null, null);
+
+ verifyXMLErrorNode(children.item(1), ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, "mock error2", null, null);
+ }
+
+ @Test
+ public void testToResponseWithAcceptHeader() throws Exception {
+
+ stageMockEx(new RestconfDocumentedException("mock error"));
+
+ final Response resp = target("/operational/foo").request().header("Accept", MediaType.APPLICATION_JSON).get();
+
+ final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_JSON, Status.INTERNAL_SERVER_ERROR);
+
+ verifyJsonResponseBody(stream, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null);
+ }
+
+ @Test
+ @Ignore
+ public void testToResponseWithStatusOnly() throws Exception {
+
+ // The StructuredDataToJsonProvider should throw a
+ // RestconfDocumentedException with no data
+
+ when(mockRestConf.readOperationalData(any(String.class), any(UriInfo.class))).thenReturn(
+ new NormalizedNodeContext(null, null));
+
+ final Response resp = target("/operational/foo").request(MediaType.APPLICATION_JSON).get();
+
+ verifyResponse(resp, MediaType.TEXT_PLAIN, Status.NOT_FOUND);
+ }
+
+ InputStream verifyResponse(final Response resp, final String expMediaType, final Status expStatus) {
+ assertEquals("getMediaType", MediaType.valueOf(expMediaType), resp.getMediaType());
+ assertEquals("getStatus", expStatus.getStatusCode(), resp.getStatus());
+
+ final Object entity = resp.getEntity();
+ assertEquals("Response entity", true, entity instanceof InputStream);
+ final InputStream stream = (InputStream) entity;
+ return stream;
+ }
+
+ void verifyJsonResponseBody(final InputStream stream, final ErrorType expErrorType, final ErrorTag expErrorTag,
+ final String expErrorMessage, final String expErrorAppTag, final ErrorInfoVerifier errorInfoVerifier)
+ throws Exception {
+
+ final JsonArray arrayElement = parseJsonErrorArrayElement(stream);
+
+ assertEquals("\"error\" Json array element length", 1, arrayElement.size());
+
+ verifyJsonErrorNode(arrayElement.get(0), expErrorType, expErrorTag, expErrorMessage, expErrorAppTag,
+ errorInfoVerifier);
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ private static JsonArray parseJsonErrorArrayElement(final InputStream stream) throws IOException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ stream.transferTo(bos);
+
+ LOG.info("JSON: {}", bos);
+
+ JsonElement rootElement;
+ try {
+ rootElement = JsonParser.parseReader(new InputStreamReader(new ByteArrayInputStream(bos.toByteArray())));
+ } catch (final Exception e) {
+ throw new IllegalArgumentException("Invalid JSON response:\n" + bos.toString(), e);
+ }
+
+ assertTrue("Root element of Json is not an Object", rootElement.isJsonObject());
+
+ final Set<Entry<String, JsonElement>> errorsEntrySet = rootElement.getAsJsonObject().entrySet();
+ assertEquals("Json Object element set count", 1, errorsEntrySet.size());
+
+ final Entry<String, JsonElement> errorsEntry = errorsEntrySet.iterator().next();
+ final JsonElement errorsElement = errorsEntry.getValue();
+ assertEquals("First Json element name", "errors", errorsEntry.getKey());
+ assertTrue("\"errors\" Json element is not an Object", errorsElement.isJsonObject());
+
+ final Set<Entry<String, JsonElement>> errorListEntrySet = errorsElement.getAsJsonObject().entrySet();
+ assertEquals("Root \"errors\" element child count", 1, errorListEntrySet.size());
+
+ final JsonElement errorListElement = errorListEntrySet.iterator().next().getValue();
+ assertEquals("\"errors\" child Json element name", "error", errorListEntrySet.iterator().next().getKey());
+ assertTrue("\"error\" Json element is not an Array", errorListElement.isJsonArray());
+
+ // As a final check, make sure there aren't multiple "error" array
+ // elements. Unfortunately,
+ // the call above to getAsJsonObject().entrySet() will out duplicate
+ // "error" elements. So
+ // we'll use regex on the json string to verify this.
+
+ final Matcher matcher = Pattern.compile("\"error\"[ ]*:[ ]*\\[", Pattern.DOTALL).matcher(bos.toString());
+ assertTrue("Expected 1 \"error\" element", matcher.find());
+ assertFalse("Found multiple \"error\" elements", matcher.find());
+
+ return errorListElement.getAsJsonArray();
+ }
+
+ void verifyJsonErrorNode(final JsonElement errorEntryElement, final ErrorType expErrorType,
+ final ErrorTag expErrorTag, final String expErrorMessage, final String expErrorAppTag,
+ final ErrorInfoVerifier errorInfoVerifier) {
+
+ JsonElement errorInfoElement = null;
+ final Map<String, String> leafMap = new HashMap<>();
+ for (final Entry<String, JsonElement> entry : errorEntryElement.getAsJsonObject().entrySet()) {
+ final String leafName = entry.getKey();
+ final JsonElement leafElement = entry.getValue();
+
+ if ("error-info".equals(leafName)) {
+ assertNotNull("Found unexpected \"error-info\" element", errorInfoVerifier);
+ errorInfoElement = leafElement;
+ } else {
+ assertTrue("\"error\" leaf Json element " + leafName + " is not a Primitive",
+ leafElement.isJsonPrimitive());
+
+ leafMap.put(leafName, leafElement.getAsString());
+ }
+ }
+
+ assertEquals("error-type", expErrorType.elementBody(), leafMap.remove("error-type"));
+ assertEquals("error-tag", expErrorTag.elementBody(), leafMap.remove("error-tag"));
+
+ verifyOptionalJsonLeaf(leafMap.remove("error-message"), expErrorMessage, "error-message");
+ verifyOptionalJsonLeaf(leafMap.remove("error-app-tag"), expErrorAppTag, "error-app-tag");
+
+ if (!leafMap.isEmpty()) {
+ fail("Found unexpected Json leaf elements for \"error\" element: " + leafMap);
+ }
+
+ if (errorInfoVerifier != null) {
+ assertNotNull("Missing \"error-info\" element", errorInfoElement);
+ errorInfoVerifier.verifyJson(errorInfoElement);
+ }
+ }
+
+ void verifyOptionalJsonLeaf(final String actualValue, final String expValue, final String tagName) {
+ if (expValue != null) {
+ assertEquals(tagName, expValue, actualValue);
+ } else {
+ assertNull("Found unexpected \"error\" leaf entry for: " + tagName, actualValue);
+ }
+ }
+
+ void verifyXMLResponseBody(final InputStream stream, final ErrorType expErrorType, final ErrorTag expErrorTag,
+ final String expErrorMessage, final String expErrorAppTag, final ErrorInfoVerifier errorInfoVerifier)
+ throws Exception {
+
+ final Document doc = parseXMLDocument(stream);
+
+ final NodeList children = getXMLErrorList(doc, 1);
+
+ verifyXMLErrorNode(children.item(0), expErrorType, expErrorTag, expErrorMessage, expErrorAppTag,
+ errorInfoVerifier);
+ }
+
+ private static Document parseXMLDocument(final InputStream stream) throws IOException, SAXException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ stream.transferTo(bos);
+
+ LOG.debug("XML: {}", bos);
+
+ return UntrustedXML.newDocumentBuilder().parse(new ByteArrayInputStream(bos.toByteArray()));
+ }
+
+ void verifyXMLErrorNode(final Node errorNode, final ErrorType expErrorType, final ErrorTag expErrorTag,
+ final String expErrorMessage, final String expErrorAppTag, final ErrorInfoVerifier errorInfoVerifier)
+ throws Exception {
+
+ final String errorType = (String) ERROR_TYPE.evaluate(errorNode, XPathConstants.STRING);
+ assertEquals("error-type", expErrorType.elementBody(), errorType);
+
+ final String errorTag = (String) ERROR_TAG.evaluate(errorNode, XPathConstants.STRING);
+ assertEquals("error-tag", expErrorTag.elementBody(), errorTag);
+
+ verifyOptionalXMLLeaf(errorNode, ERROR_MESSAGE, expErrorMessage, "error-message");
+ verifyOptionalXMLLeaf(errorNode, ERROR_APP_TAG, expErrorAppTag, "error-app-tag");
+
+ final Node errorInfoNode = (Node) ERROR_INFO.evaluate(errorNode, XPathConstants.NODE);
+ if (errorInfoVerifier != null) {
+ assertNotNull("Missing \"error-info\" node", errorInfoNode);
+
+ errorInfoVerifier.verifyXML(errorInfoNode);
+ } else {
+ assertNull("Found unexpected \"error-info\" node", errorInfoNode);
+ }
+ }
+
+ void verifyOptionalXMLLeaf(final Node fromNode, final XPathExpression xpath, final String expValue,
+ final String tagName) throws Exception {
+ if (expValue != null) {
+ final String actual = (String) xpath.evaluate(fromNode, XPathConstants.STRING);
+ assertEquals(tagName, expValue, actual);
+ } else {
+ assertNull("Found unexpected \"error\" leaf entry for: " + tagName,
+ xpath.evaluate(fromNode, XPathConstants.NODE));
+ }
+ }
+
+ NodeList getXMLErrorList(final Node fromNode, final int count) throws Exception {
+ final NodeList errorList = (NodeList) ERROR_LIST.evaluate(fromNode, XPathConstants.NODESET);
+ assertNotNull("Root errors node is empty", errorList);
+ assertEquals("Root errors node child count", count, errorList.getLength());
+ return errorList;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java
new file mode 100644
index 0000000..30a0449
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+/**
+ * Unit tests for RestconfError.
+ *
+ * @author Devin Avery
+ * @author Thomas Pantelis
+ *
+ */
+public class RestconfErrorTest {
+
+ static class Contains extends BaseMatcher<String> {
+
+ private final String text;
+
+ Contains(final String text) {
+ this.text = text;
+ }
+
+ @Override
+ public void describeTo(final Description desc) {
+ desc.appendText("contains ").appendValue(text);
+ }
+
+ @Override
+ public boolean matches(final Object arg) {
+ return arg != null && arg.toString().contains(text);
+ }
+ }
+
+ @Test
+ public void testRestConfDocumentedException_NoCause() {
+ String expectedMessage = "Message";
+ ErrorType expectedErrorType = ErrorType.RPC;
+ ErrorTag expectedErrorTag = ErrorTag.IN_USE;
+ RestconfError error = new RestconfError(expectedErrorType, expectedErrorTag, expectedMessage);
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag, null, (String) null, error);
+ }
+
+ @Test
+ public void testRestConfDocumentedException_WithAppTag() {
+ String expectedMessage = "Message";
+ ErrorType expectedErrorType = ErrorType.RPC;
+ ErrorTag expectedErrorTag = ErrorTag.IN_USE;
+ String expectedErrorAppTag = "application.tag";
+
+ RestconfError error =
+ new RestconfError(expectedErrorType, expectedErrorTag, expectedMessage, expectedErrorAppTag);
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag, expectedErrorAppTag, (String) null,
+ error);
+ }
+
+ @Test
+ public void testRestConfDocumentedException_WithAppTagErrorInfo() {
+ String expectedMessage = "Message";
+ ErrorType expectedErrorType = ErrorType.RPC;
+ ErrorTag expectedErrorTag = ErrorTag.IN_USE;
+ String expectedErrorAppTag = "application.tag";
+ String errorInfo = "<extra><sessionid>session.id</sessionid></extra>";
+
+ RestconfError error =
+ new RestconfError(expectedErrorType, expectedErrorTag, expectedMessage, expectedErrorAppTag, errorInfo);
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag, expectedErrorAppTag, errorInfo,
+ error);
+ }
+
+ @Test
+ public void testRestConfErrorWithRpcError() {
+
+ // All fields set
+ RpcError rpcError = RpcResultBuilder.newError(ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock error-message",
+ "mock app-tag", "mock error-info", new Exception("mock cause"));
+
+ validateRestConfError("mock error-message", ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock app-tag",
+ "mock error-info", new RestconfError(rpcError));
+
+ // All fields set except 'info' - expect error-info set to 'cause'
+ rpcError = RpcResultBuilder.newError(ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock error-message",
+ "mock app-tag", null, new Exception("mock cause"));
+
+ validateRestConfError("mock error-message", ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock app-tag",
+ new Contains("mock cause"), new RestconfError(rpcError));
+
+ // Some fields set - expect error-info set to ErrorSeverity
+ rpcError = RpcResultBuilder.newError(ErrorType.RPC, ErrorTag.ACCESS_DENIED, null, null, null, null);
+
+ validateRestConfError(null, ErrorType.RPC, ErrorTag.ACCESS_DENIED, null, "<severity>error</severity>",
+ new RestconfError(rpcError));
+
+ // 'tag' field not mapped to ErrorTag - expect error-tag set to OPERATION_FAILED
+ rpcError = RpcResultBuilder.newWarning(ErrorType.TRANSPORT, new ErrorTag("not mapped"), null, null, null, null);
+
+ validateRestConfError(null, ErrorType.TRANSPORT, new ErrorTag("not mapped"), null,
+ "<severity>warning</severity>", new RestconfError(rpcError));
+
+ // No fields set - edge case
+ rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, null, null, null, null, null);
+
+ validateRestConfError(null, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED,
+ null, "<severity>error</severity>", new RestconfError(rpcError));
+ }
+
+ private static void validateRestConfError(final String expectedMessage, final ErrorType expectedErrorType,
+ final ErrorTag expectedErrorTag, final String expectedErrorAppTag, final String errorInfo,
+ final RestconfError error) {
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag, expectedErrorAppTag,
+ equalTo(errorInfo), error);
+ }
+
+ private static void validateRestConfError(final String expectedMessage, final ErrorType expectedErrorType,
+ final ErrorTag expectedErrorTag, final String expectedErrorAppTag, final Matcher<String> errorInfoMatcher,
+ final RestconfError error) {
+
+ assertEquals("getErrorMessage", expectedMessage, error.getErrorMessage());
+ assertEquals("getErrorType", expectedErrorType, error.getErrorType());
+ assertEquals("getErrorTag", expectedErrorTag, error.getErrorTag());
+ assertEquals("getErrorAppTag", expectedErrorAppTag, error.getErrorAppTag());
+ assertThat("getErrorInfo", error.getErrorInfo(), errorInfoMatcher);
+ error.toString(); // really just checking for NPE etc. Don't care about
+ // contents.
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java
new file mode 100644
index 0000000..b69d105
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.time.Instant;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.netconf.sal.streams.websockets.WebSocketServer;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class RestconfImplNotificationSubscribingTest {
+
+ private final String identifier = "data-change-event-subscription/datastore=OPERATIONAL/scope=ONE";
+
+ private static EffectiveModelContext schemaContext;
+
+ @Mock
+ private BrokerFacade broker;
+
+ @Mock
+ private UriInfo uriInfo;
+
+ private ControllerContext controllerContext;
+ private RestconfImpl restconfImpl;
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ schemaContext = YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/notifications"));
+ }
+
+ @AfterClass
+ public static void cleanUp() {
+ WebSocketServer.destroyInstance(); // NETCONF-604
+ }
+
+ @Before
+ public void setup() {
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ restconfImpl = RestconfImpl.newInstance(broker, controllerContext);
+
+ final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class);
+ Notificator.createListener(path, identifier, NotificationOutputType.XML, controllerContext);
+ }
+
+ @Test
+ public void startTimeTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test
+ public void milisecsTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00.12345Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test
+ public void zonesPlusTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00+01:00"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test
+ public void zonesMinusTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00-01:00"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test
+ public void startAndStopTimeTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00Z")),
+ Map.entry("stop-time", List.of("2014-10-25T12:31:00Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test(expected = RestconfDocumentedException.class)
+ public void stopTimeTest() {
+ subscribe(Set.of(Map.entry("stop-time", List.of("2014-10-25T12:31:00Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test(expected = RestconfDocumentedException.class)
+ public void badParamTest() {
+ subscribe(Set.of(Map.entry("time", List.of("2014-10-25T12:31:00Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void badValueTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("badvalue"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void badZonesTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00Z+1:00"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void badMilisecsTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00:0026Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test
+ public void onNotifiTest() throws Exception {
+ final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class);
+ final PathArgument pathValue = NodeIdentifier.create(QName.create("module", "2016-12-14", "localName"));
+ final ListenerAdapter listener = Notificator.createListener(path, identifier, NotificationOutputType.XML,
+ controllerContext);
+
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00Z"))));
+
+ Instant startOrig = listener.getStart();
+ assertNotNull(startOrig);
+ listener.onDataTreeChanged(List.of());
+
+ startOrig = listener.getStart();
+ assertNull(startOrig);
+ }
+
+ private void subscribe(final Set<Entry<String, List<String>>> entries) {
+ final MultivaluedMap<String, String> map = mock(MultivaluedMap.class);
+ when(uriInfo.getQueryParameters()).thenReturn(map);
+ final UriBuilder uriBuilder = UriBuilder.fromPath("http://localhost:8181/" + identifier);
+ when(uriInfo.getAbsolutePathBuilder()).thenReturn(uriBuilder);
+ when(map.entrySet()).thenReturn(entries);
+ restconfImpl.subscribeToStream(identifier, uriInfo);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java
new file mode 100644
index 0000000..3174908
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
+
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.netconf.sal.streams.websockets.WebSocketServer;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.Empty;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.stmt.InputEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.OutputEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+/**
+ * See {@link InvokeRpcMethodTest}.
+ */
+public class RestconfImplTest {
+
+ private static EffectiveModelContext schemaContext;
+
+ private final BrokerFacade brokerFacade = mock(BrokerFacade.class);
+ private final ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ private final RestconfImpl restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs", "/modules/restconf-module-testing");
+ }
+
+ @AfterClass
+ public static void cleanUp() {
+ WebSocketServer.destroyInstance(); // NETCONF-604
+ }
+
+ @Test
+ public void binaryKeyTest() {
+ final List<Byte> al = new ArrayList<>();
+ al.add((byte) 1);
+ binaryKeyTest(al, al);
+ }
+
+ private static void binaryKeyTest(final List<Byte> al, final List<Byte> al2) {
+
+ final QName keyDef = QName.create("test:key:binary", "2017-08-14", "b1");
+
+ final Map<QName, Object> uriKeyValues = new HashMap<>();
+ uriKeyValues.put(keyDef, al.toArray());
+
+ final MapEntryNode payload = mock(MapEntryNode.class);
+ final NodeIdentifierWithPredicates nodeIdWithPred =
+ NodeIdentifierWithPredicates.of(keyDef, keyDef, al2.toArray());
+ when(payload.getIdentifier()).thenReturn(nodeIdWithPred);
+
+ final List<QName> keyDefinitions = new ArrayList<>();
+ keyDefinitions.add(keyDef);
+ RestconfImpl.isEqualUriAndPayloadKeyValues(uriKeyValues, payload, keyDefinitions);
+ }
+
+ @Test
+ public void binaryKeyFailTest() {
+ final List<Byte> al = new ArrayList<>();
+ al.add((byte) 1);
+ final List<Byte> al2 = new ArrayList<>();
+ try {
+ binaryKeyTest(al, al2);
+ } catch (final RestconfDocumentedException e) {
+ final RestconfError err = e.getErrors().iterator().next();
+ assertEquals(ErrorType.PROTOCOL, err.getErrorType());
+ assertEquals(ErrorTag.INVALID_VALUE, err.getErrorTag());
+ }
+ }
+
+ @Test
+ public void testExample() throws FileNotFoundException, ParseException {
+ final NormalizedNode normalizedNodeData = TestUtils.prepareNormalizedNodeWithIetfInterfacesInterfacesData();
+ when(brokerFacade.readOperationalData(isNull())).thenReturn(normalizedNodeData);
+ assertEquals(normalizedNodeData,
+ brokerFacade.readOperationalData(null));
+ }
+
+ @Test
+ public void testRpcForMountpoint() throws Exception {
+ final QName qname = QName.create("namespace", "2010-10-10", "localname");
+ final UriInfo uriInfo = mock(UriInfo.class);
+ doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters(anyBoolean());
+
+ final NormalizedNodeContext ctx = mock(NormalizedNodeContext.class);
+ final RpcDefinition rpc = mock(RpcDefinition.class,
+ withSettings().extraInterfaces(RpcEffectiveStatement.class));
+ doReturn(qname).when(rpc).getQName();
+
+ final InputSchemaNode input = mock(InputSchemaNode.class,
+ withSettings().extraInterfaces(InputEffectiveStatement.class));
+ final QName inputQName = YangConstants.operationInputQName(qname.getModule());
+ doReturn(input).when(rpc).getInput();
+ doReturn(inputQName).when(input).getQName();
+ doReturn(Optional.of(input)).when((RpcEffectiveStatement) rpc).findSchemaTreeNode(inputQName);
+
+ final OutputSchemaNode output = mock(OutputSchemaNode.class,
+ withSettings().extraInterfaces(OutputEffectiveStatement.class));
+ final QName outputQName = YangConstants.operationInputQName(qname.getModule());
+ doReturn(output).when(rpc).getOutput();
+ doReturn(outputQName).when(output).getQName();
+ doReturn(Optional.of(output)).when((RpcEffectiveStatement) rpc).findSchemaTreeNode(outputQName);
+
+ final EffectiveModelContext mountContext = mock(EffectiveModelContext.class);
+ final ModuleEffectiveStatement mountModule = mock(ModuleEffectiveStatement.class);
+ doReturn(Map.of(qname.getModule(), mountModule)).when(mountContext).getModuleStatements();
+ doReturn(Optional.of(rpc)).when(mountModule).findSchemaTreeNode(qname);
+
+ final DOMMountPoint mount = mock(DOMMountPoint.class);
+ doReturn(Optional.of(FixedDOMSchemaService.of(mountContext))).when(mount).getService(DOMSchemaService.class);
+
+ doReturn(InstanceIdentifierContext.ofRpcInput(mountContext, rpc, mount))
+ .when(ctx).getInstanceIdentifierContext();
+
+ final DOMRpcService rpcService = mock(DOMRpcService.class);
+ doReturn(Optional.of(rpcService)).when(mount).getService(DOMRpcService.class);
+ doReturn(immediateFluentFuture(mock(DOMRpcResult.class))).when(rpcService)
+ .invokeRpc(any(QName.class), any(NormalizedNode.class));
+ restconfImpl.invokeRpc("randomId", ctx, uriInfo);
+ restconfImpl.invokeRpc("ietf-netconf", ctx, uriInfo);
+ verify(rpcService, times(2)).invokeRpc(any(QName.class), any());
+ }
+
+ /**
+ * Create notification stream for toaster module.
+ */
+ @Test
+ public void createNotificationStreamTest() {
+ final QName rpcQName = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "2014-01-14", "create-notification-stream");
+
+ final RpcDefinition schemaNode = schemaContext.getOperations().stream()
+ .filter(rpc -> rpc.getQName().equals(rpcQName))
+ .findFirst()
+ .orElseThrow();
+
+ final NormalizedNodeContext payload = mock(NormalizedNodeContext.class);
+ doReturn(InstanceIdentifierContext.ofRpcInput(schemaContext, schemaNode, null)).when(payload)
+ .getInstanceIdentifierContext();
+
+ final Set<DataContainerChild> children = new HashSet<>();
+ final LeafSetNode child = mock(LeafSetNode.class);
+
+ final LeafSetEntryNode entryNode = mock(LeafSetEntryNode.class);
+ when(entryNode.body()).thenReturn("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)toastDone");
+ when(child.body()).thenReturn(Set.of(entryNode));
+ children.add(child);
+
+ final ContainerNode normalizedNode = mock(ContainerNode.class);
+ doReturn(normalizedNode).when(payload).getData();
+ doReturn(children).when(normalizedNode).body();
+
+ // register notification
+ final NormalizedNodeContext context = restconfImpl
+ .invokeRpc("sal-remote:create-notification-stream", payload, null);
+ assertNotNull(context);
+ }
+
+ /**
+ * Tests stream entry node.
+ */
+ @Test
+ public void toStreamEntryNodeTest() {
+ final Module restconfModule = controllerContext.getRestconfModule();
+ final DataSchemaNode streamSchemaNode = controllerContext
+ .getRestconfModuleRestConfSchemaNode(restconfModule, Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE);
+ final ListSchemaNode listStreamSchemaNode = (ListSchemaNode) streamSchemaNode;
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamNodeValues =
+ SchemaAwareBuilders.mapEntryBuilder(listStreamSchemaNode);
+ var instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "name");
+ final DataSchemaNode nameSchemaNode = instanceDataChildrenByName.get(0).child;
+ streamNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) nameSchemaNode)
+ .withValue("")
+ .build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "description");
+ final DataSchemaNode descriptionSchemaNode = instanceDataChildrenByName.get(0).child;
+ streamNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) nameSchemaNode)
+ .withValue("DESCRIPTION_PLACEHOLDER")
+ .build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "replay-support");
+ final DataSchemaNode replaySupportSchemaNode = instanceDataChildrenByName.get(0).child;
+ streamNodeValues.withChild(
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) replaySupportSchemaNode).withValue(Boolean.TRUE).build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "replay-log-creation-time");
+ final DataSchemaNode replayLogCreationTimeSchemaNode = instanceDataChildrenByName.get(0).child;
+ streamNodeValues.withChild(
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) replayLogCreationTimeSchemaNode).withValue("").build());
+ instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "events");
+ final DataSchemaNode eventsSchemaNode = instanceDataChildrenByName.get(0).child;
+ streamNodeValues.withChild(
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) eventsSchemaNode).withValue(Empty.value()).build());
+ assertNotNull(streamNodeValues.build());
+ }
+
+ /**
+ * Subscribe for notification stream of toaster module.
+ */
+ @Test
+ public void subscribeToNotificationStreamTest() throws Exception {
+ final String identifier = "create-notification-stream/toaster:toastDone";
+
+ // register test notification stream
+ Notificator.createNotificationListener(
+ List.of(Absolute.of(QName.create("http://netconfcentral.org/ns/toaster", "2009-11-20", "toastDone"))),
+ identifier, "XML", controllerContext);
+
+ final UriInfo uriInfo = mock(UriInfo.class);
+ final UriBuilder uriBuilder = mock(UriBuilder.class);
+ when(uriBuilder.port(8181)).thenReturn(uriBuilder);
+ when(uriBuilder.replacePath(identifier)).thenReturn(uriBuilder);
+ when(uriBuilder.build()).thenReturn(new URI(""));
+ when(uriBuilder.scheme("ws")).thenReturn(uriBuilder);
+ when(uriInfo.getAbsolutePathBuilder()).thenReturn(uriBuilder);
+ final MultivaluedMap<String, String> map = mock(MultivaluedMap.class);
+ final Set<Entry<String, List<String>>> set = new HashSet<>();
+ when(map.entrySet()).thenReturn(set);
+ when(uriInfo.getQueryParameters()).thenReturn(map);
+
+ // subscribe to stream and verify response
+ final NormalizedNodeContext response = restconfImpl.subscribeToStream(identifier, uriInfo);
+
+ // remove test notification stream
+ Notificator.removeAllListeners();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
new file mode 100644
index 0000000..d96cc77
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public final class TestUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class);
+
+ private TestUtils() {
+
+ }
+
+ public static EffectiveModelContext loadSchemaContext(final String... yangPath) throws FileNotFoundException {
+ final List<File> files = new ArrayList<>();
+ for (final String path : yangPath) {
+ final String pathToFile = TestUtils.class.getResource(path).getPath();
+ final File testDir = new File(pathToFile);
+ final String[] fileList = testDir.list();
+ if (fileList == null) {
+ throw new FileNotFoundException(pathToFile);
+ }
+
+ for (final String fileName : fileList) {
+ final File file = new File(testDir, fileName);
+ if (file.isDirectory() == false) {
+ files.add(file);
+ }
+ }
+ }
+
+ return YangParserTestUtils.parseYangFiles(files);
+ }
+
+ public static Module findModule(final Collection<? extends Module> modules, final String moduleName) {
+ for (final Module module : modules) {
+ if (module.getName().equals(moduleName)) {
+ return module;
+ }
+ }
+ return null;
+ }
+
+ public static Document loadDocumentFrom(final InputStream inputStream) {
+ try {
+ return UntrustedXML.newDocumentBuilder().parse(inputStream);
+ } catch (SAXException | IOException e) {
+ LOG.error("Error during loading Document from XML", e);
+ return null;
+ }
+ }
+
+ public static String getDocumentInPrintableForm(final Document doc) {
+ try {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final TransformerFactory tf = TransformerFactory.newInstance();
+ final Transformer transformer = tf.newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+
+ transformer.transform(new DOMSource(requireNonNull(doc)), new StreamResult(new OutputStreamWriter(out,
+ StandardCharsets.UTF_8)));
+ final byte[] charData = out.toByteArray();
+ return new String(charData, StandardCharsets.UTF_8);
+ } catch (final TransformerException e) {
+ final String msg = "Error during transformation of Document into String";
+ LOG.error(msg, e);
+ return msg;
+ }
+
+ }
+
+ /**
+ * Searches module with name {@code searchedModuleName} in {@code modules}. If module name isn't specified and
+ * module set has only one element then this element is returned.
+ *
+ */
+ public static Module resolveModule(final String searchedModuleName, final Collection<? extends Module> modules) {
+ assertNotNull("Modules can't be null.", modules);
+ if (searchedModuleName != null) {
+ for (final Module m : modules) {
+ if (m.getName().equals(searchedModuleName)) {
+ return m;
+ }
+ }
+ } else if (modules.size() == 1) {
+ return modules.iterator().next();
+ }
+ return null;
+ }
+
+ public static DataSchemaNode resolveDataSchemaNode(final String searchedDataSchemaName, final Module module) {
+ assertNotNull("Module can't be null", module);
+
+ if (searchedDataSchemaName != null) {
+ for (final DataSchemaNode dsn : module.getChildNodes()) {
+ if (dsn.getQName().getLocalName().equals(searchedDataSchemaName)) {
+ return dsn;
+ }
+ }
+ } else if (module.getChildNodes().size() == 1) {
+ return module.getChildNodes().iterator().next();
+ }
+ return null;
+ }
+
+ public static QName buildQName(final String name, final String uri, final String date, final String prefix) {
+ return QName.create(XMLNamespace.of(uri), Revision.ofNullable(date), name);
+ }
+
+ public static QName buildQName(final String name, final String uri, final String date) {
+ return buildQName(name, uri, date, null);
+ }
+
+ public static QName buildQName(final String name) {
+ return buildQName(name, "", null);
+ }
+
+ public static String loadTextFile(final String filePath) throws IOException {
+ final FileReader fileReader = new FileReader(filePath, StandardCharsets.UTF_8);
+ final BufferedReader bufReader = new BufferedReader(fileReader);
+
+ String line = null;
+ final StringBuilder result = new StringBuilder();
+ while ((line = bufReader.readLine()) != null) {
+ result.append(line);
+ }
+ bufReader.close();
+ return result.toString();
+ }
+
+ private static Pattern patternForStringsSeparatedByWhiteChars(final String... substrings) {
+ final StringBuilder pattern = new StringBuilder();
+ pattern.append(".*");
+ for (final String substring : substrings) {
+ pattern.append(substring);
+ pattern.append("\\s*");
+ }
+ pattern.append(".*");
+ return Pattern.compile(pattern.toString(), Pattern.DOTALL);
+ }
+
+ public static boolean containsStringData(final String jsonOutput, final String... substrings) {
+ final Pattern pattern = patternForStringsSeparatedByWhiteChars(substrings);
+ final Matcher matcher = pattern.matcher(jsonOutput);
+ return matcher.matches();
+ }
+
+ public static NodeIdentifier getNodeIdentifier(final String localName, final String namespace,
+ final String revision) throws ParseException {
+ return new NodeIdentifier(QName.create(namespace, revision, localName));
+ }
+
+ public static NodeIdentifierWithPredicates getNodeIdentifierPredicate(final String localName,
+ final String namespace, final String revision, final Map<String, Object> keys) throws ParseException {
+ final Map<QName, Object> predicate = new HashMap<>();
+ for (final String key : keys.keySet()) {
+ predicate.put(QName.create(namespace, revision, key), keys.get(key));
+ }
+
+ return NodeIdentifierWithPredicates.of(QName.create(namespace, revision, localName), predicate);
+ }
+
+ public static NodeIdentifierWithPredicates getNodeIdentifierPredicate(final String localName,
+ final String namespace, final String revision, final String... keysAndValues) throws ParseException {
+ checkArgument(keysAndValues.length % 2 == 0, "number of keys argument have to be divisible by 2 (map)");
+ final Map<QName, Object> predicate = new HashMap<>();
+
+ int index = 0;
+ while (index < keysAndValues.length) {
+ predicate.put(QName.create(namespace, revision, keysAndValues[index++]), keysAndValues[index++]);
+ }
+
+ return NodeIdentifierWithPredicates.of(QName.create(namespace, revision, localName), predicate);
+ }
+
+ public static NormalizedNode prepareNormalizedNodeWithIetfInterfacesInterfacesData() throws ParseException {
+ final String ietfInterfacesDate = "2013-07-04";
+ final String namespace = "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryNode =
+ ImmutableMapEntryNodeBuilder.create();
+
+ final Map<String, Object> predicates = new HashMap<>();
+ predicates.put("name", "eth0");
+
+ mapEntryNode.withNodeIdentifier(getNodeIdentifierPredicate("interface", namespace, ietfInterfacesDate,
+ predicates));
+ mapEntryNode
+ .withChild(new ImmutableLeafNodeBuilder<String>()
+ .withNodeIdentifier(getNodeIdentifier("name", namespace, ietfInterfacesDate)).withValue("eth0")
+ .build());
+ mapEntryNode.withChild(new ImmutableLeafNodeBuilder<String>()
+ .withNodeIdentifier(getNodeIdentifier("type", namespace, ietfInterfacesDate))
+ .withValue("ethernetCsmacd").build());
+ mapEntryNode.withChild(new ImmutableLeafNodeBuilder<Boolean>()
+ .withNodeIdentifier(getNodeIdentifier("enabled", namespace, ietfInterfacesDate))
+ .withValue(Boolean.FALSE).build());
+ mapEntryNode.withChild(new ImmutableLeafNodeBuilder<String>()
+ .withNodeIdentifier(getNodeIdentifier("description", namespace, ietfInterfacesDate))
+ .withValue("some interface").build());
+
+ return mapEntryNode.build();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java
new file mode 100644
index 0000000..1b61ea1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static java.util.Objects.requireNonNull;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.CreateDataChangeEventSubscriptionInput1.Scope;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class URIParametersParsing {
+
+ private RestconfImpl restconf;
+ private BrokerFacade mockedBrokerFacade;
+ private ControllerContext controllerContext;
+
+ @Before
+ public void init() throws FileNotFoundException, ReactorException {
+ mockedBrokerFacade = mock(BrokerFacade.class);
+ controllerContext = TestRestconfUtils.newControllerContext(
+ TestUtils.loadSchemaContext("/datastore-and-scope-specification"));
+ restconf = RestconfImpl.newInstance(mockedBrokerFacade, controllerContext);
+ }
+
+ @Test
+ public void resolveURIParametersConcreteValues() {
+ resolveURIParameters("OPERATIONAL", "SUBTREE", LogicalDatastoreType.OPERATIONAL, Scope.SUBTREE);
+ }
+
+ @Test
+ public void resolveURIParametersDefaultValues() {
+ resolveURIParameters(null, null, LogicalDatastoreType.CONFIGURATION, Scope.BASE);
+ }
+
+ private void resolveURIParameters(final String datastore, final String scope,
+ final LogicalDatastoreType datastoreExpected, final Scope scopeExpected) {
+
+ final InstanceIdentifierBuilder iiBuilder = YangInstanceIdentifier.builder();
+ iiBuilder.node(QName.create("", "dummyStreamName"));
+
+ final String datastoreValue = datastore == null ? "CONFIGURATION" : datastore;
+ final String scopeValue = scope == null ? "BASE" : scope + "";
+ Notificator.createListener(iiBuilder.build(), "dummyStreamName/datastore=" + datastoreValue + "/scope="
+ + scopeValue, NotificationOutputType.XML, controllerContext);
+
+ final UriInfo mockedUriInfo = mock(UriInfo.class);
+ @SuppressWarnings("unchecked")
+ final MultivaluedMap<String, String> mockedMultivaluedMap = mock(MultivaluedMap.class);
+ when(mockedMultivaluedMap.getFirst(eq("datastore"))).thenReturn(datastoreValue);
+ when(mockedMultivaluedMap.getFirst(eq("scope"))).thenReturn(scopeValue);
+
+ when(mockedUriInfo.getQueryParameters(eq(false))).thenReturn(mockedMultivaluedMap);
+
+ final UriBuilder uriBuilder = UriBuilder.fromUri("www.whatever.com");
+ when(mockedUriInfo.getAbsolutePathBuilder()).thenReturn(uriBuilder);
+
+ restconf.invokeRpc("sal-remote:create-data-change-event-subscription",
+ prepareDomRpcNode(datastoreValue, scopeValue), mockedUriInfo);
+
+ final ListenerAdapter listener =
+ Notificator.getListenerFor("data-change-event-subscription/opendaylight-inventory:nodes/datastore="
+ + datastoreValue + "/scope=" + scopeValue);
+ assertNotNull(listener);
+ }
+
+ private NormalizedNodeContext prepareDomRpcNode(final String datastore, final String scope) {
+ final EffectiveModelContext schema = controllerContext.getGlobalSchema();
+ final Module rpcSalRemoteModule = schema.findModule("sal-remote", Revision.of("2014-01-14")).get();
+ final QName rpcQName =
+ QName.create(rpcSalRemoteModule.getQNameModule(), "create-data-change-event-subscription");
+ final RpcDefinition rpcDef = Mockito.mock(RpcDefinition.class);
+ ContainerLike rpcInputSchemaNode = null;
+ for (final RpcDefinition rpc : rpcSalRemoteModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcInputSchemaNode = rpc.getInput();
+ break;
+ }
+ }
+ assertNotNull("RPC ContainerSchemaNode was not found!", rpcInputSchemaNode);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> container =
+ SchemaAwareBuilders.containerBuilder(rpcInputSchemaNode);
+
+ final QName pathQName =
+ QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "2014-01-14", "path");
+ final DataSchemaNode pathSchemaNode = rpcInputSchemaNode.getDataChildByName(pathQName);
+ assertTrue(pathSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> pathNode = SchemaAwareBuilders.leafBuilder((LeafSchemaNode) pathSchemaNode)
+ .withValue(YangInstanceIdentifier.builder()
+ .node(QName.create("urn:opendaylight:inventory", "2013-08-19", "nodes")).build()).build();
+ container.withChild(pathNode);
+
+ final AugmentationSchemaNode augmentationSchema = requireNonNull(rpcInputSchemaNode.getAvailableAugmentations()
+ .iterator().next());
+ final DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> augmentationBuilder =
+ SchemaAwareBuilders.augmentationBuilder(augmentationSchema);
+
+ final QName dataStoreQName = QName.create("urn:sal:restconf:event:subscription", "2014-07-08", "datastore");
+ final DataSchemaNode dsSchemaNode = augmentationSchema.getDataChildByName(dataStoreQName);
+ assertTrue(dsSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> dsNode = SchemaAwareBuilders.leafBuilder((LeafSchemaNode) dsSchemaNode)
+ .withValue(datastore).build();
+ augmentationBuilder.withChild(dsNode);
+
+ final QName scopeQName = QName.create("urn:sal:restconf:event:subscription", "2014-07-08", "scope");
+ final DataSchemaNode scopeSchemaNode = augmentationSchema.getDataChildByName(scopeQName);
+ assertTrue(scopeSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> scopeNode = SchemaAwareBuilders.leafBuilder((LeafSchemaNode) scopeSchemaNode)
+ .withValue(scope).build();
+ augmentationBuilder.withChild(scopeNode);
+
+ final QName outputQName =
+ QName.create("urn:sal:restconf:event:subscription", "2014-07-08", "notification-output-type");
+ final DataSchemaNode outputSchemaNode = augmentationSchema.getDataChildByName(outputQName);
+ assertTrue(outputSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> outputNode =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) outputSchemaNode).withValue("XML").build();
+ augmentationBuilder.withChild(outputNode);
+
+ container.withChild(augmentationBuilder.build());
+
+ when(rpcDef.getInput()).thenReturn((InputSchemaNode) rpcInputSchemaNode);
+ when(rpcDef.getQName()).thenReturn(rpcQName);
+
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofRpcInput(schema, rpcDef, null), container.build());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java
new file mode 100644
index 0000000..8178674
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.io.FileNotFoundException;
+import java.util.Optional;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class URITest {
+
+ private static EffectiveModelContext schemaContext;
+ private static EffectiveModelContext mountSchemaContext;
+
+ private final DOMMountPoint mountInstance = mock(DOMMountPoint.class);
+ private final ControllerContext controllerContext =
+ TestRestconfUtils.newControllerContext(schemaContext, mountInstance);
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs");
+ mountSchemaContext = TestUtils.loadSchemaContext("/test-config-data/yang2");
+ }
+
+ @Test
+ public void testToInstanceIdentifierList() {
+ InstanceIdentifierContext instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:userWithoutClass/foo");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass");
+
+ instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:userWithoutClass/foo");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass");
+
+ instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:user/foo/boo");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "user");
+
+ instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:user//boo");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "user");
+
+ }
+
+ @Test
+ public void testToInstanceIdentifierWithDoubleSlash() {
+ InstanceIdentifierContext instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:food//nonalcoholic");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "nonalcoholic");
+
+ instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:userWithoutClass//");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass");
+
+ instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:userWithoutClass///inner-container");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "inner-container");
+ }
+
+ @Test
+ public void testToInstanceIdentifierListWithNullKey() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:user/null/boo"));
+ }
+
+ @Test
+ public void testToInstanceIdentifierListWithMissingKey() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:user/foo"));
+ }
+
+ @Test
+ public void testToInstanceIdentifierContainer() {
+ final InstanceIdentifierContext instanceIdentifier =
+ controllerContext.toInstanceIdentifier("simple-nodes:users");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "users");
+ assertTrue(instanceIdentifier.getSchemaNode() instanceof ContainerSchemaNode);
+ assertEquals(2, ((ContainerSchemaNode) instanceIdentifier.getSchemaNode()).getChildNodes().size());
+ }
+
+ @Test
+ public void testToInstanceIdentifierChoice() {
+ final InstanceIdentifierContext instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:food/nonalcoholic");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "nonalcoholic");
+ }
+
+ @Test
+ public void testToInstanceIdentifierChoiceException() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:food/snack"));
+ }
+
+ @Test
+ public void testToInstanceIdentifierCaseException() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:food/sports-arena"));
+ }
+
+ @Test
+ public void testToInstanceIdentifierChoiceCaseException() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:food/snack/sports-arena"));
+ }
+
+ @Test
+ public void testToInstanceIdentifierWithoutNode() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes"));
+ }
+
+ @Test
+ public void testMountPointWithExternModul() {
+ initSchemaService();
+ final InstanceIdentifierContext instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:users/yang-ext:mount/test-interface2:class/student/name");
+ assertEquals(
+ "[(urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)class, "
+ + "(urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)student, "
+ + "(urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)student"
+ + "[{(urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)name=name}]]",
+ ImmutableList.copyOf(instanceIdentifier.getInstanceIdentifier().getPathArguments()).toString());
+ }
+
+ @Test
+ public void testMountPointWithoutExternModul() {
+ initSchemaService();
+ final InstanceIdentifierContext instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:users/yang-ext:mount/");
+ assertTrue(Iterables.isEmpty(instanceIdentifier.getInstanceIdentifier().getPathArguments()));
+ }
+
+ @Test
+ public void testMountPointWithoutMountPointSchema() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:users/yang-ext:mount/test-interface2:class"));
+ }
+
+ private void initSchemaService() {
+ doReturn(Optional.of(FixedDOMSchemaService.of(mountSchemaContext))).when(mountInstance)
+ .getService(DOMSchemaService.class);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java
new file mode 100644
index 0000000..b0dd7a2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ dataLoad("/instanceidentifier/yang", 4, "instance-identifier-module", "cont");
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java
new file mode 100644
index 0000000..df13bb8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class XmlAndJsonToCnSnLeafRefTest extends YangAndXmlAndDataSchemaLoader {
+
+ final QName refContQName = QName.create("referenced:module", "2014-04-17", "cont");
+ final QName refLf1QName = QName.create(this.refContQName, "lf1");
+ final QName contQName = QName.create("leafref:module", "2014-04-17", "cont");
+ final QName lf1QName = QName.create(this.contQName, "lf1");
+ final QName lf2QName = QName.create(this.contQName, "lf2");
+ final QName lf3QName = QName.create(this.contQName, "lf3");
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ dataLoad("/leafref/yang", 2, "leafref-module", "cont");
+ }
+
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlAndDataSchemaLoader.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlAndDataSchemaLoader.java
new file mode 100644
index 0000000..9192691
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlAndDataSchemaLoader.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.FileNotFoundException;
+import java.util.Collection;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+public abstract class YangAndXmlAndDataSchemaLoader {
+ protected static Collection<? extends Module> modules;
+ protected static DataSchemaNode dataSchemaNode;
+ protected static String searchedModuleName;
+ protected static String searchedDataSchemaName;
+ protected static String schemaNodePath;
+
+ protected static void dataLoad(final String yangPath) throws FileNotFoundException {
+ dataLoad(yangPath, 1, null, null);
+ }
+
+ protected static void dataLoad(final String yangPath, final int modulesNumber, final String moduleName,
+ final String dataSchemaName) throws FileNotFoundException {
+ modules = TestUtils.loadSchemaContext(yangPath).getModules();
+ assertEquals(modulesNumber, modules.size());
+ final Module module = TestUtils.resolveModule(moduleName, modules);
+ searchedModuleName = module == null ? "" : module.getName();
+ assertNotNull(module);
+ dataSchemaNode = TestUtils.resolveDataSchemaNode(dataSchemaName, module);
+ searchedDataSchemaName = dataSchemaNode == null ? "" : dataSchemaNode.getQName().getLocalName();
+ assertNotNull(dataSchemaNode);
+ schemaNodePath = searchedModuleName + ":" + searchedDataSchemaName;
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModule.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModule.java
new file mode 100644
index 0000000..cabdc6c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModule.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2019 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test.incubate;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import javax.annotation.PreDestroy;
+import javax.inject.Singleton;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractBaseDataBrokerTest;
+import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMMountPointService;
+import org.opendaylight.mdsal.dom.api.DOMNotificationPublishService;
+import org.opendaylight.mdsal.dom.api.DOMNotificationService;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.broker.DOMMountPointServiceImpl;
+import org.opendaylight.mdsal.dom.broker.DOMNotificationRouter;
+import org.opendaylight.mdsal.dom.broker.DOMRpcRouter;
+import org.opendaylight.mdsal.dom.spi.DOMNotificationSubscriptionListenerRegistry;
+import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider;
+
+/**
+ * Guice Module which binds the mdsal (not controller) {@link DataBroker} & Co.
+ * in-memory implementation suitable for tests.
+ *
+ * <p>This class is here only temporarily and it can and should be removed and
+ * replaced when the equivalent will be offered by the mdsal project itself; see
+ * <a href="https://jira.opendaylight.org/browse/MDSAL-418">MDSAL-418</a>. It is
+ * also copy/pasted to org.opendaylight.restconf.nb.rfc8040.test.incubate.InMemoryMdsalModule.
+ *
+ * <p>BEWARE: Do *NOT* use this module in component tests or applications mixing
+ * code requiring the old controller and the new mdsal {@link DataBroker} & Co.
+ * APIs together - because this binds a *SEPARATE* {@link InMemoryDOMDataStore},
+ * and doesn't delegate to controller's InMemoryDOMDataStore. This is just fine
+ * for tests where all code under test already uses only the mdsal APIs.
+ *
+ * @author Michael Vorburger.ch
+ */
+public class InMemoryMdsalModule extends AbstractModule {
+
+ private static final int NOTIFICATION_SERVICE_QUEUE_DEPTH = 128;
+
+ private final AbstractBaseDataBrokerTest dataBrokerTest;
+ private final DOMNotificationRouter domNotificationRouter;
+
+ public InMemoryMdsalModule() throws Exception {
+ dataBrokerTest = new AbstractConcurrentDataBrokerTest(true) { // NOT AbstractDataBrokerTest
+ };
+ dataBrokerTest.setup();
+
+ domNotificationRouter = DOMNotificationRouter.create(NOTIFICATION_SERVICE_QUEUE_DEPTH);
+ }
+
+ @Override
+ protected void configure() {
+ }
+
+ @Provides
+ @Singleton
+ DataBroker getDataBroker() {
+ return dataBrokerTest.getDataBroker();
+ }
+
+ @Provides
+ @Singleton DOMDataBroker getDOMDataBroker() {
+ return dataBrokerTest.getDomBroker();
+ }
+
+ @Provides
+ @Singleton DOMNotificationRouter getDOMNotificationRouter() {
+ return dataBrokerTest.getDataBrokerTestCustomizer().getDomNotificationRouter();
+ }
+
+ @Provides
+ @Singleton DOMSchemaService getSchemaService() {
+ return dataBrokerTest.getDataBrokerTestCustomizer().getSchemaService();
+ }
+
+ @Provides
+ @Singleton EffectiveModelContextProvider getSchemaContextProvider() {
+ DOMSchemaService schemaService = dataBrokerTest.getDataBrokerTestCustomizer().getSchemaService();
+ if (schemaService instanceof EffectiveModelContextProvider) {
+ return (EffectiveModelContextProvider) schemaService;
+ }
+ throw new IllegalStateException(
+ "The schema service isn't a SchemaContextProvider, it's a " + schemaService.getClass());
+ }
+
+ @Provides
+ @Singleton DOMMountPointService getDOMMountPoint() {
+ return new DOMMountPointServiceImpl();
+ }
+
+ @Provides
+ @Singleton DOMNotificationService getDOMNotificationService() {
+ return domNotificationRouter;
+ }
+
+ @Provides
+ @Singleton DOMNotificationPublishService getDOMNotificationPublishService() {
+ return domNotificationRouter;
+ }
+
+ @Provides
+ @Singleton DOMNotificationSubscriptionListenerRegistry getDOMNotificationSubscriptionListenerRegistry() {
+ return domNotificationRouter;
+ }
+
+ @Provides
+ @Singleton DOMRpcService getDOMRpcService(DOMSchemaService schemaService) {
+ return DOMRpcRouter.newInstance(schemaService).getRpcService();
+ }
+
+ @PreDestroy
+ public void close() {
+ // TODO When moving this to mdsal, must close components to shut down Threads etc.
+ // but cannot do this here (in netconf) yet, because we need to change AbstractBaseDataBrokerTest & Co..
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModuleTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModuleTest.java
new file mode 100644
index 0000000..6e01ecd
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModuleTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test.incubate;
+
+import java.util.concurrent.ExecutionException;
+import javax.inject.Inject;
+import org.junit.Rule;
+import org.junit.Test;
+import org.opendaylight.infrautils.inject.guice.testutils.AnnotationsModule;
+import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+
+/**
+ * Test for {@link InMemoryMdsalModule}.
+ *
+ * <p>This will be removed when the local {@link InMemoryMdsalModule} incubating here
+ * in netconf will be replaced by the one from mdsal.
+ *
+ * @author Michael Vorburger.ch
+ */
+public class InMemoryMdsalModuleTest {
+
+ public @Rule GuiceRule guice = new GuiceRule(InMemoryMdsalModule.class, AnnotationsModule.class);
+
+ @Inject DataBroker dataBroker;
+
+ @Test public void testDataBroker() throws InterruptedException, ExecutionException {
+ dataBroker.newReadWriteTransaction().commit().get();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java
new file mode 100644
index 0000000..a5323fb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.restconf.impl.websockets.client;
+
+/**
+ * Created by mbobak on 1/22/14.
+ */
+public interface IClientMessageCallback {
+
+ void onMessageReceived(Object message);
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java
new file mode 100644
index 0000000..a67a491
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.websockets.client;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
+import io.netty.handler.codec.http.websocketx.WebSocketVersion;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketClient {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketClient.class);
+
+ private final URI uri;
+ private final Bootstrap bootstrap = new Bootstrap();
+ private final WebSocketClientHandler clientHandler;
+ private Channel clientChannel;
+ private final EventLoopGroup group = new NioEventLoopGroup();
+
+ public WebSocketClient(final URI uri, final IClientMessageCallback clientMessageCallback) {
+ this.uri = uri;
+ clientHandler = new WebSocketClientHandler(WebSocketClientHandshakerFactory.newHandshaker(uri,
+ WebSocketVersion.V13, null, false, null), clientMessageCallback);
+ // last null could be replaced with DefaultHttpHeaders
+ initialize();
+ }
+
+ private void initialize() {
+
+ String protocol = uri.getScheme();
+ if (!"ws".equals(protocol)) {
+ throw new IllegalArgumentException("Unsupported protocol: " + protocol);
+ }
+
+ bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
+ @Override
+ public void initChannel(final SocketChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+ pipeline.addLast("http-codec", new HttpClientCodec());
+ pipeline.addLast("aggregator", new HttpObjectAggregator(8192));
+ pipeline.addLast("ws-handler", clientHandler);
+ }
+ });
+ }
+
+ public void connect() throws InterruptedException {
+ LOG.info("WebSocket Client connecting");
+ clientChannel = bootstrap.connect(uri.getHost(), uri.getPort()).sync().channel();
+ clientHandler.handshakeFuture().sync();
+ }
+
+ public void writeAndFlush(final String message) {
+ clientChannel.writeAndFlush(new TextWebSocketFrame(message));
+ }
+
+ public void writeAndFlush(final Object message) {
+ clientChannel.writeAndFlush(message);
+ }
+
+ public void ping() {
+ clientChannel.writeAndFlush(new PingWebSocketFrame(Unpooled.copiedBuffer(new byte[] { 1, 2, 3, 4, 5, 6 })));
+ }
+
+ public void close(final String reasonText) throws InterruptedException {
+ CloseWebSocketFrame closeWebSocketFrame = new CloseWebSocketFrame(1000, reasonText);
+ clientChannel.writeAndFlush(closeWebSocketFrame);
+
+ // WebSocketClientHandler will close the connection when the server
+ // responds to the CloseWebSocketFrame.
+ clientChannel.closeFuture().sync();
+ group.shutdownGracefully();
+ }
+
+ public static void main(final String[] args) throws Exception {
+ URI uri;
+ if (args.length > 0) {
+ uri = new URI(args[0]);
+ } else {
+ uri = new URI("http://192.168.1.101:8181/opendaylight-inventory:nodes");
+ }
+ IClientMessageCallback messageCallback = new ClientMessageCallback();
+ WebSocketClient webSocketClient = new WebSocketClient(uri, messageCallback);
+ webSocketClient.connect();
+
+ while (true) {
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ String input = br.readLine();
+ if (input.equals("q")) {
+ LOG.info("Would you like to close stream? (Y = yes, empty = yes)\n");
+ input = br.readLine();
+ if (input.equals("yes") || input.isEmpty()) {
+ webSocketClient.close("opendaylight-inventory:nodes");
+ break;
+ }
+ }
+ }
+ }
+
+ private static class ClientMessageCallback implements IClientMessageCallback {
+ @Override
+ public void onMessageReceived(final Object message) {
+ if (message instanceof TextWebSocketFrame) {
+ LOG.info("received message {}" + ((TextWebSocketFrame) message).text());
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java
new file mode 100644
index 0000000..19dbbc3
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.websockets.client;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
+import io.netty.handler.codec.http.websocketx.WebSocketFrame;
+import io.netty.util.CharsetUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketClientHandler.class.toString());
+ private final WebSocketClientHandshaker handshaker;
+ private ChannelPromise handshakeFuture;
+ private final IClientMessageCallback messageListener;
+
+ public WebSocketClientHandler(final WebSocketClientHandshaker handshaker, final IClientMessageCallback listener) {
+ this.handshaker = handshaker;
+ this.messageListener = listener;
+ }
+
+ public ChannelFuture handshakeFuture() {
+ return handshakeFuture;
+ }
+
+ @Override
+ public void handlerAdded(final ChannelHandlerContext ctx) throws Exception {
+ handshakeFuture = ctx.newPromise();
+ }
+
+ @Override
+ public void channelActive(final ChannelHandlerContext ctx) throws Exception {
+ handshaker.handshake(ctx.channel());
+ }
+
+ @Override
+ public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
+ LOG.info("WebSocket Client disconnected!");
+ }
+
+ @Override
+ public void channelRead0(final ChannelHandlerContext ctx, final Object msg) throws Exception {
+ Channel ch = ctx.channel();
+ if (!handshaker.isHandshakeComplete()) {
+ handshaker.finishHandshake(ch, (FullHttpResponse) msg);
+ LOG.info("WebSocket Client connected!");
+ handshakeFuture.setSuccess();
+ return;
+ }
+
+ if (msg instanceof FullHttpResponse) {
+ FullHttpResponse response = (FullHttpResponse) msg;
+ throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.status() + ", content="
+ + response.content().toString(CharsetUtil.UTF_8) + ')');
+ }
+
+ messageListener.onMessageReceived(msg);
+ WebSocketFrame frame = (WebSocketFrame) msg;
+
+ if (frame instanceof PongWebSocketFrame) {
+ LOG.info("WebSocket Client received pong");
+ } else if (frame instanceof CloseWebSocketFrame) {
+ LOG.info("WebSocket Client received closing");
+ ch.close();
+ }
+ }
+
+ @Override
+ public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
+ LOG.info("Cause: {} .", cause.toString());
+
+ if (!handshakeFuture.isDone()) {
+ handshakeFuture.setFailure(cause);
+ }
+
+ ctx.close();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStreamTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStreamTest.java
new file mode 100644
index 0000000..0163ce0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStreamTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.websockets.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.io.FileNotFoundException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+public class RestStreamTest extends JerseyTest {
+
+ private static EffectiveModelContext schemaContextYangsIetf;
+
+ private BrokerFacade brokerFacade;
+ private RestconfImpl restconfImpl;
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ final ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContextYangsIetf);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl, new NormalizedNodeJsonBodyWriter(),
+ new NormalizedNodeXmlBodyWriter(), new XmlNormalizedNodeBodyReader(controllerContext),
+ new JsonNormalizedNodeBodyReader(controllerContext),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ @Test
+ @Ignore // Sporadic failures where jersey does not correctly pass post data to XmlNormalizedNodeBodyReader.readFrom
+ public void testCallRpcCallGet() throws UnsupportedEncodingException, InterruptedException {
+ createAndSubscribe(null);
+ }
+
+ @Test
+ @Ignore // Sporadic failures where jersey does not correctly pass post data to XmlNormalizedNodeBodyReader.readFrom
+ public void testCallRpcCallGetLeaves() throws UnsupportedEncodingException, InterruptedException {
+ createAndSubscribe("odl-leaf-nodes-only", "true");
+ }
+
+ private void createAndSubscribe(final String queryParamName, final Object... values)
+ throws UnsupportedEncodingException, InterruptedException {
+ String uri = "/operations/sal-remote:create-data-change-event-subscription";
+ String rpcInput = getRpcInput();
+ final Response responseWithStreamName = post(uri, MediaType.APPLICATION_XML, rpcInput);
+ final Document xmlResponse = responseWithStreamName.readEntity(Document.class);
+ assertNotNull(xmlResponse);
+ final Element outputElement = xmlResponse.getDocumentElement();
+ assertEquals("output",outputElement.getLocalName());
+
+ final Node streamNameElement = outputElement.getFirstChild();
+ assertEquals("stream-name",streamNameElement.getLocalName());
+ assertEquals("data-change-event-subscription/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0/"
+ + "datastore=CONFIGURATION/scope=BASE",streamNameElement.getTextContent());
+
+ uri = "/streams/stream/data-change-event-subscription/ietf-interfaces:interfaces/ietf-interfaces:interface/"
+ + "eth0/datastore=CONFIGURATION/scope=BASE";
+ final Response responseWithRedirectionUri = get(uri, MediaType.APPLICATION_XML, null);
+ final URI websocketServerUri = responseWithRedirectionUri.getLocation();
+ assertNotNull(websocketServerUri);
+ assertTrue(websocketServerUri.toString().matches(".*ws://localhost:[\\d]+/data-change-event-subscription/"
+ + "ietf-interfaces:interfaces/ietf-interfaces:interface/eth0.*"));
+ }
+
+ private Response post(final String uri, final String mediaType, final String data) {
+ return target(uri).request(mediaType).post(Entity.entity(data, mediaType));
+ }
+
+ private Response get(final String uri, final String mediaType, final String queryParam, final Object... values) {
+ if (queryParam != null) {
+ return target(uri).queryParam(queryParam, values).request(mediaType).get();
+ } else {
+ return target(uri).request(mediaType).get();
+ }
+ }
+
+ private static String getRpcInput() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("<input xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote\">");
+ sb.append("<path xmlns:int=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">/"
+ + "int:interfaces/int:interface[int:name='eth0']</path>");
+ sb.append("</input>");
+ return sb.toString();
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java
new file mode 100644
index 0000000..2a6f7de
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test;
+
+
+public class XmlAugmentedElementToCnSnTest {
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java
new file mode 100644
index 0000000..1cac018
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class XmlToCnSnTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ dataLoad("/xml-to-cnsn/leafref");
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriterTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriterTest.java
new file mode 100644
index 0000000..58debcb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriterTest.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.rest.impl;
+
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Optional;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+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;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class DepthAwareNormalizedNodeWriterTest {
+
+ @Mock
+ private NormalizedNodeStreamWriter writer;
+ @Mock
+ private ContainerNode containerNodeData;
+ @Mock
+ private MapNode mapNodeData;
+ @Mock
+ private MapEntryNode mapEntryNodeData;
+ @Mock
+ private LeafSetNode<String> leafSetNodeData;
+ @Mock
+ private LeafSetEntryNode<String> leafSetEntryNodeData;
+ @Mock
+ private LeafNode<String> keyLeafNodeData;
+ @Mock
+ private LeafNode<String> anotherLeafNodeData;
+
+ private NodeIdentifier containerNodeIdentifier;
+ private NodeIdentifier mapNodeIdentifier;
+ private NodeIdentifierWithPredicates mapEntryNodeIdentifier;
+ private NodeIdentifier leafSetNodeIdentifier;
+ private NodeWithValue<String> leafSetEntryNodeIdentifier;
+ private NodeIdentifier keyLeafNodeIdentifier;
+ private NodeIdentifier anotherLeafNodeIdentifier;
+
+ private Collection<DataContainerChild> containerNodeValue;
+ private Collection<MapEntryNode> mapNodeValue;
+ private Collection<DataContainerChild> mapEntryNodeValue;
+ private Collection<LeafSetEntryNode<String>> leafSetNodeValue;
+ private String leafSetEntryNodeValue;
+ private String keyLeafNodeValue;
+ private String anotherLeafNodeValue;
+
+ @Before
+ public void setUp() {
+ // identifiers
+ containerNodeIdentifier = NodeIdentifier.create(QName.create("namespace", "container"));
+ when(containerNodeData.getIdentifier()).thenReturn(containerNodeIdentifier);
+
+ mapNodeIdentifier = NodeIdentifier.create(QName.create("namespace", "list"));
+ when(mapNodeData.getIdentifier()).thenReturn(mapNodeIdentifier);
+
+ final QName leafSetEntryNodeQName = QName.create("namespace", "leaf-set-entry");
+ leafSetEntryNodeValue = "leaf-set-value";
+ leafSetEntryNodeIdentifier = new NodeWithValue<>(leafSetEntryNodeQName, leafSetEntryNodeValue);
+ when(leafSetEntryNodeData.getIdentifier()).thenReturn(leafSetEntryNodeIdentifier);
+
+ leafSetNodeIdentifier = NodeIdentifier.create(QName.create("namespace", "leaf-set"));
+ when(leafSetNodeData.getIdentifier()).thenReturn(leafSetNodeIdentifier);
+
+ final QName mapEntryNodeKey = QName.create("namespace", "key-field");
+ keyLeafNodeIdentifier = NodeIdentifier.create(mapEntryNodeKey);
+ keyLeafNodeValue = "key-value";
+
+ mapEntryNodeIdentifier = NodeIdentifierWithPredicates.of(
+ QName.create("namespace", "list-entry"), mapEntryNodeKey, keyLeafNodeValue);
+ when(mapEntryNodeData.getIdentifier()).thenReturn(mapEntryNodeIdentifier);
+ when(mapEntryNodeData.findChildByArg(keyLeafNodeIdentifier)).thenReturn(Optional.of(keyLeafNodeData));
+
+ when(keyLeafNodeData.body()).thenReturn(keyLeafNodeValue);
+ when(keyLeafNodeData.getIdentifier()).thenReturn(keyLeafNodeIdentifier);
+
+ anotherLeafNodeIdentifier = NodeIdentifier.create(QName.create("namespace", "another-field"));
+ anotherLeafNodeValue = "another-value";
+
+ when(anotherLeafNodeData.body()).thenReturn(anotherLeafNodeValue);
+ when(anotherLeafNodeData.getIdentifier()).thenReturn(anotherLeafNodeIdentifier);
+
+ // values
+ when(leafSetEntryNodeData.body()).thenReturn(leafSetEntryNodeValue);
+
+ leafSetNodeValue = Collections.singletonList(leafSetEntryNodeData);
+ when(leafSetNodeData.body()).thenReturn(leafSetNodeValue);
+
+ containerNodeValue = Collections.singleton(leafSetNodeData);
+ when(containerNodeData.body()).thenReturn(containerNodeValue);
+
+ mapEntryNodeValue = Sets.newHashSet(keyLeafNodeData, anotherLeafNodeData);
+ when(mapEntryNodeData.body()).thenReturn(mapEntryNodeValue);
+
+ mapNodeValue = Collections.singleton(mapEntryNodeData);
+ when(mapNodeData.body()).thenReturn(mapNodeValue);
+ }
+
+ /**
+ * Test write {@link ContainerNode} with children but write data only to depth 1 (children will not be written).
+ */
+ @Test
+ public void writeContainerWithoutChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(writer, 1);
+
+ depthWriter.write(containerNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startContainerNode(containerNodeIdentifier, containerNodeValue.size());
+ inOrder.verify(writer, times(1)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write {@link ContainerNode} with children and write also all its children.
+ */
+ @Test
+ public void writeContainerWithChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, Integer.MAX_VALUE);
+
+ depthWriter.write(containerNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startContainerNode(containerNodeIdentifier, containerNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafSet(leafSetNodeIdentifier, leafSetNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafSetEntryNode(leafSetEntryNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(leafSetEntryNodeValue);
+ inOrder.verify(writer, times(3)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link MapNode} with children but write data only to depth 1 (children will not be written).
+ */
+ @Test
+ public void writeMapNodeWithoutChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(writer, 1);
+
+ depthWriter.write(mapNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startMapNode(mapNodeIdentifier, mapNodeValue.size());
+ inOrder.verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(3)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write {@link MapNode} with children and write also all its children.
+ * FIXME
+ * Although ordered writer is used leaves are not written in expected order.
+ *
+ */
+ @Ignore
+ @Test
+ public void writeMapNodeWithChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, Integer.MAX_VALUE);
+
+ depthWriter.write(mapNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startMapNode(mapNodeIdentifier, mapNodeValue.size());
+ inOrder.verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(1)).endNode();
+ inOrder.verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(1)).endNode();
+
+ // FIXME this assertion is not working because leaves are not written in expected order
+ inOrder.verify(writer, times(1)).startLeafNode(anotherLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(anotherLeafNodeValue);
+ inOrder.verify(writer, times(3)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link LeafSetNode} with depth 1 (children will not be written).
+ */
+ @Test
+ public void writeLeafSetNodeWithoutChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, 1);
+
+ depthWriter.write(leafSetNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startLeafSet(leafSetNodeIdentifier, leafSetNodeValue.size());
+ inOrder.verify(writer, times(1)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link LeafSetNode} when all its children will be written.
+ */
+ @Test
+ public void writeLeafSetNodeWithChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, Integer.MAX_VALUE);
+
+ depthWriter.write(leafSetNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startLeafSet(leafSetNodeIdentifier, leafSetNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafSetEntryNode(leafSetEntryNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(leafSetEntryNodeValue);
+ inOrder.verify(writer, times(2)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link LeafSetEntryNode}.
+ */
+ @Test
+ public void writeLeafSetEntryNodeTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, Integer.MAX_VALUE);
+
+ depthWriter.write(leafSetEntryNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startLeafSetEntryNode(leafSetEntryNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(leafSetEntryNodeValue);
+ inOrder.verify(writer, times(1)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link MapEntryNode} unordered to depth 1 to write only keys.
+ */
+ @Test
+ public void writeMapEntryNodeUnorderedOnlyKeysTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, false, 1);
+
+ depthWriter.write(mapEntryNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ // write only the key
+ inOrder.verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(2)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link MapEntryNode} unordered with full depth.
+ */
+ @Test
+ public void writeMapEntryNodeUnorderedTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, false, Integer.MAX_VALUE);
+
+ depthWriter.write(mapEntryNodeData);
+
+ // unordered
+ verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ verify(writer, times(1)).startLeafNode(anotherLeafNodeIdentifier);
+ verify(writer, times(1)).scalarValue(anotherLeafNodeValue);
+ verify(writer, times(3)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link MapEntryNode} ordered with depth 1 (children will not be written).
+ */
+ @Test
+ public void writeMapEntryNodeOrderedWithoutChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, true, 1);
+
+ depthWriter.write(mapEntryNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(2)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link MapEntryNode} ordered and write also all its children.
+ * FIXME
+ * Although ordered writer is used leaves are not written in expected order.
+ *
+ */
+ @Ignore
+ @Test
+ public void writeMapEntryNodeOrderedTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, true, Integer.MAX_VALUE);
+
+ depthWriter.write(mapEntryNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ inOrder.verify(writer, times(2)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(2)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(1)).endNode();
+ // FIXME this assertion is not working because leaves are not written in expected order
+ inOrder.verify(writer, times(1)).startLeafNode(anotherLeafNodeIdentifier);
+ inOrder.verify(writer, times(2)).scalarValue(anotherLeafNodeValue);
+ inOrder.verify(writer, times(2)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/restconf/impl/InstanceIdentifierCodecImplTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/restconf/impl/InstanceIdentifierCodecImplTest.java
new file mode 100644
index 0000000..e0d48bb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/restconf/impl/InstanceIdentifierCodecImplTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.io.FileNotFoundException;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.restconf.impl.RestCodec.InstanceIdentifierCodecImpl;
+import org.opendaylight.restconf.common.util.IdentityValuesDTO;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class InstanceIdentifierCodecImplTest {
+ private static EffectiveModelContext schemaContext;
+
+ private InstanceIdentifierCodecImpl instanceIdentifierDTO;
+ private YangInstanceIdentifier instanceIdentifierBadNamespace;
+ private YangInstanceIdentifier instanceIdentifierOKList;
+ private YangInstanceIdentifier instanceIdentifierOKLeafList;
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ schemaContext = YangParserTestUtils.parseYangFiles(
+ TestRestconfUtils.loadFiles("/restconf/parser/deserializer"));
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+
+ this.instanceIdentifierDTO = new InstanceIdentifierCodecImpl(null, controllerContext);
+
+ final QName baseQName = QName.create("deserializer:test", "2016-06-06", "deserializer-test");
+ final QName contA = QName.create(baseQName, "contA");
+ final QName leafList = QName.create(baseQName, "leaf-list-A");
+
+ this.instanceIdentifierOKLeafList = YangInstanceIdentifier.builder()
+ .node(contA)
+ .node(new YangInstanceIdentifier.NodeWithValue<>(leafList, "instance"))
+ .build();
+
+ this.instanceIdentifierOKList = YangInstanceIdentifier.builder()
+ .node(NodeIdentifierWithPredicates.of(
+ QName.create(baseQName, "list-one-key"),
+ QName.create(QName.create(baseQName, "list-one-key"), "name"), "value"))
+ .build();
+
+ this.instanceIdentifierBadNamespace = YangInstanceIdentifier.builder()
+ .nodeWithKey(QName.create("nonexistent:module", "2016-10-17", "nonexistent-1"),
+ QName.create("nonexistent:module", "2016-10-17", "nonexistent"),
+ "value")
+ .build();
+ }
+
+ @Test
+ public void testSerializeDeserializeList() throws Exception {
+ final IdentityValuesDTO valuesDTO =
+ this.instanceIdentifierDTO.serialize(this.instanceIdentifierOKList);
+
+ final YangInstanceIdentifier deserializedIdentifier =
+ this.instanceIdentifierDTO.deserialize(valuesDTO);
+ assertEquals(this.instanceIdentifierOKList, deserializedIdentifier);
+ }
+
+ @Test
+ public void testSerializeDeserializeLeafList() throws Exception {
+ final IdentityValuesDTO valuesDTO =
+ this.instanceIdentifierDTO.serialize(this.instanceIdentifierOKLeafList);
+
+ final YangInstanceIdentifier deserializedIdentifier =
+ this.instanceIdentifierDTO.deserialize(valuesDTO);
+ assertEquals(this.instanceIdentifierOKLeafList, deserializedIdentifier);
+ }
+
+ @Test
+ public void testSerializeDeserializeBadModuleNamespace() throws Exception {
+ final IdentityValuesDTO valuesDTO =
+ this.instanceIdentifierDTO.serialize(this.instanceIdentifierBadNamespace);
+ assertEquals("nonexistent-1", valuesDTO.getValuesWithNamespaces().get(0).getValue());
+ assertEquals("nonexistent:module", valuesDTO.getValuesWithNamespaces().get(0).getNamespace());
+
+ final YangInstanceIdentifier deserializedIdentifier =
+ this.instanceIdentifierDTO.deserialize(valuesDTO);
+ assertNull(deserializedIdentifier);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java
new file mode 100644
index 0000000..453f077
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2017 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import static java.time.Instant.EPOCH;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Optional;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.PatchCont;
+import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1;
+import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1Builder;
+import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1Key;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest {
+ private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapterTest.class);
+
+ private static final String JSON_NOTIF_LEAVES_CREATE = "/listener-adapter-test/notif-leaves-create.json";
+ private static final String JSON_NOTIF_LEAVES_UPDATE = "/listener-adapter-test/notif-leaves-update.json";
+ private static final String JSON_NOTIF_LEAVES_DEL = "/listener-adapter-test/notif-leaves-del.json";
+ private static final String JSON_NOTIF_CREATE = "/listener-adapter-test/notif-create.json";
+ private static final String JSON_NOTIF_UPDATE = "/listener-adapter-test/notif-update.json";
+ private static final String JSON_NOTIF_DEL = "/listener-adapter-test/notif-del.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_CREATE =
+ "/listener-adapter-test/notif-without-data-create.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_UPDATE =
+ "/listener-adapter-test/notif-without-data-update.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_DELETE =
+ "/listener-adapter-test/notif-without-data-del.json";
+
+
+ private static final YangInstanceIdentifier PATCH_CONT_YIID =
+ YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(PatchCont.QNAME));
+
+ private static EffectiveModelContext schemaContext;
+
+ private DataBroker dataBroker;
+ private DOMDataBroker domDataBroker;
+ private ControllerContext controllerContext;
+
+ @BeforeClass
+ public static void init() {
+ schemaContext = YangParserTestUtils.parseYangResource(
+ "/instanceidentifier/yang/instance-identifier-patch-module.yang");
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ dataBroker = getDataBroker();
+ domDataBroker = getDomBroker();
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ }
+
+ class ListenerAdapterTester extends ListenerAdapter {
+
+ private String lastNotification = null;
+
+ ListenerAdapterTester(final YangInstanceIdentifier path, final String streamName,
+ final NotificationOutputTypeGrouping.NotificationOutputType outputType,
+ final boolean leafNodesOnly, final boolean skipNotificationData) {
+ super(path, streamName, outputType, controllerContext);
+ setQueryParams(EPOCH, Optional.empty(), Optional.empty(), leafNodesOnly, skipNotificationData);
+ }
+
+ @Override
+ protected void post(final Event event) {
+ this.lastNotification = event.getData();
+ }
+
+ public void assertGot(final String json) throws Exception {
+ long start = System.currentTimeMillis();
+ while (true) {
+ if (lastNotification != null) {
+ break;
+ }
+ if (System.currentTimeMillis() - start > 1000) {
+ throw new Exception("TIMED OUT waiting for notification with " + json);
+ }
+ Thread.currentThread();
+ Thread.sleep(200);
+ }
+ LOG.debug("Comparing {} {}", json, lastNotification);
+ JSONAssert.assertEquals(json, withFakeDate(lastNotification), false);
+ this.lastNotification = null;
+ }
+ }
+
+ static String withFakeDate(final String in) {
+ JSONObject doc = new JSONObject(in);
+ JSONObject notification = doc.getJSONObject("notification");
+ if (notification == null) {
+ return in;
+ }
+ notification.put("eventTime", "someDate");
+ return doc.toString();
+ }
+
+ private String getNotifJson(final String path) throws IOException, URISyntaxException {
+ URL url = getClass().getResource(path);
+ byte[] bytes = Files.readAllBytes(Paths.get(url.toURI()));
+ return withFakeDate(new String(bytes, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ public void testJsonNotifsLeaves() throws Exception {
+ ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, true, false);
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(DOMDataTreeChangeService.class);
+ DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
+ changeService.registerDataTreeChangeListener(root, adapter);
+
+ WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+ MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
+ InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
+ .child(MyList1.class, new MyList1Key("Althea"));
+ writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_CREATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
+ writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_UPDATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_DEL));
+ }
+
+ @Test
+ public void testJsonNotifs() throws Exception {
+ ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, false, false);
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(DOMDataTreeChangeService.class);
+ DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
+ changeService.registerDataTreeChangeListener(root, adapter);
+
+ WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+ MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
+ InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
+ .child(MyList1.class, new MyList1Key("Althea"));
+ writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_CREATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
+ writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_UPDATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_DEL));
+ }
+
+ @Test
+ public void testJsonNotifsWithoutData() throws Exception {
+ ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, false, true);
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(DOMDataTreeChangeService.class);
+ DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
+ changeService.registerDataTreeChangeListener(root, adapter);
+
+ WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+ MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
+ InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
+ .child(MyList1.class, new MyList1Key("Althea"));
+ writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_CREATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
+ writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_UPDATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_DELETE));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerTest.java
new file mode 100644
index 0000000..732c327
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.streams.listeners;
+
+import static java.util.Objects.requireNonNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.mdsal.dom.api.DOMNotification;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class NotificationListenerTest {
+ private static final QNameModule MODULE = QNameModule.create(XMLNamespace.of("notifi:mod"),
+ Revision.of("2016-11-23"));
+
+ private static EffectiveModelContext schemaContext;
+
+ private ControllerContext controllerContext;
+
+ @BeforeClass
+ public static void staticInit() throws FileNotFoundException {
+ schemaContext = TestUtils.loadSchemaContext("/notifications");
+ }
+
+ @Before
+ public void init() {
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ }
+
+ @Test
+ public void notifi_leafTest() {
+ final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-leaf"));
+
+ final DOMNotification notificationData = mock(DOMNotification.class);
+
+ final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf"));
+ final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), leaf);
+
+ when(notificationData.getType()).thenReturn(schemaPathNotifi);
+ when(notificationData.getBody()).thenReturn(notifiBody);
+
+ final String result = prepareJson(notificationData, schemaPathNotifi);
+
+ assertTrue(result.contains("ietf-restconf:notification"));
+ assertTrue(result.contains("event-time"));
+ assertTrue(result.contains("notifi-module:notifi-leaf"));
+ assertTrue(result.contains("lf" + '"' + ":" + '"' + "value"));
+ }
+
+ @Test
+ public void notifi_cont_leafTest() {
+ final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-cont"));
+
+ final DOMNotification notificationData = mock(DOMNotification.class);
+
+ final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf"));
+ final ContainerNode cont = mockCont(QName.create(MODULE, "cont"), leaf);
+ final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), cont);
+
+ when(notificationData.getType()).thenReturn(schemaPathNotifi);
+ when(notificationData.getBody()).thenReturn(notifiBody);
+
+ final String result = prepareJson(notificationData, schemaPathNotifi);
+
+ assertTrue(result.contains("ietf-restconf:notification"));
+ assertTrue(result.contains("event-time"));
+ assertTrue(result.contains("notifi-module:notifi-cont"));
+ assertTrue(result.contains("cont"));
+ assertTrue(result.contains("lf" + '"' + ":" + '"' + "value"));
+ }
+
+ @Test
+ public void notifi_list_Test() {
+ final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-list"));
+
+ final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), ImmutableNodes.mapNodeBuilder()
+ .withNodeIdentifier(NodeIdentifier.create(QName.create(MODULE, "lst")))
+ .withChild(mockMapEntry(QName.create(MODULE, "lst"), mockLeaf(QName.create(MODULE, "lf"))))
+ .build());
+
+ final DOMNotification notificationData = mock(DOMNotification.class);
+ when(notificationData.getType()).thenReturn(schemaPathNotifi);
+ when(notificationData.getBody()).thenReturn(notifiBody);
+
+ final String result = prepareJson(notificationData, schemaPathNotifi);
+
+ assertTrue(result.contains("ietf-restconf:notification"));
+ assertTrue(result.contains("event-time"));
+ assertTrue(result.contains("notifi-module:notifi-list"));
+ assertTrue(result.contains("lst"));
+ assertTrue(result.contains("lf" + '"' + ":" + '"' + "value"));
+ }
+
+ @Test
+ public void notifi_grpTest() {
+ final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-grp"));
+
+ final DOMNotification notificationData = mock(DOMNotification.class);
+
+ final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf"));
+ final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), leaf);
+
+ when(notificationData.getType()).thenReturn(schemaPathNotifi);
+ when(notificationData.getBody()).thenReturn(notifiBody);
+
+ final String result = prepareJson(notificationData, schemaPathNotifi);
+
+ assertTrue(result.contains("ietf-restconf:notification"));
+ assertTrue(result.contains("event-time"));
+ assertTrue(result.contains("lf" + '"' + ":" + '"' + "value"));
+ }
+
+ @Test
+ public void notifi_augmTest() {
+ final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-augm"));
+
+ final DOMNotification notificationData = mock(DOMNotification.class);
+
+ final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf-augm"));
+ final AugmentationNode augm = mockAugm(leaf);
+ final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), augm);
+
+ when(notificationData.getType()).thenReturn(schemaPathNotifi);
+ when(notificationData.getBody()).thenReturn(notifiBody);
+
+ final String result = prepareJson(notificationData, schemaPathNotifi);
+
+ assertTrue(result.contains("ietf-restconf:notification"));
+ assertTrue(result.contains("event-time"));
+ assertTrue(result.contains("lf-augm" + '"' + ":" + '"' + "value"));
+ }
+
+ private static AugmentationNode mockAugm(final LeafNode<String> leaf) {
+ final AugmentationNode augm = mock(AugmentationNode.class);
+ final AugmentationIdentifier augmId = new AugmentationIdentifier(Set.of(leaf.getIdentifier().getNodeType()));
+ when(augm.getIdentifier()).thenReturn(augmId);
+
+ final Collection<DataContainerChild> childs = new ArrayList<>();
+ childs.add(leaf);
+
+ when(augm.body()).thenReturn(childs);
+ return augm;
+ }
+
+ private static MapEntryNode mockMapEntry(final QName entryQName, final LeafNode<String> leaf) {
+ return Builders.mapEntryBuilder()
+ .withNodeIdentifier(NodeIdentifierWithPredicates.of(entryQName, leaf.getIdentifier().getNodeType(),
+ leaf.body()))
+ .withChild(leaf)
+ .build();
+ }
+
+ private static ContainerNode mockCont(final QName contQName, final DataContainerChild child) {
+ return Builders.containerBuilder()
+ .withNodeIdentifier(NodeIdentifier.create(contQName))
+ .withChild(child)
+ .build();
+ }
+
+ private static LeafNode<String> mockLeaf(final QName leafQName) {
+ return ImmutableNodes.leafNode(leafQName, "value");
+ }
+
+ private String prepareJson(final DOMNotification notificationData, final Absolute schemaPathNotifi) {
+ final List<NotificationListenerAdapter> listNotifi = Notificator.createNotificationListener(
+ List.of(schemaPathNotifi), "stream-name", NotificationOutputType.JSON.toString(), controllerContext);
+ final NotificationListenerAdapter notifi = listNotifi.get(0);
+ return requireNonNull(notifi.prepareJson(schemaContext, notificationData));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilderTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilderTest.java
new file mode 100644
index 0000000..f3ab6f9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilderTest.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+
+public class DatastoreIdentifierBuilderTest {
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testDatastoreIdentifierBuilder() {
+ final DatastoreIdentifierBuilder datastoreIdentifierBuilder = new DatastoreIdentifierBuilder();
+ assertNotNull(datastoreIdentifierBuilder);
+ DatastoreIdentifierBuilder.getDefaultInstance("");
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleBuilderTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleBuilderTest.java
new file mode 100644
index 0000000..a834b15
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleBuilderTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import org.junit.Test;
+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.restconf.rev131019.RevisionIdentifier;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier;
+
+public class ModuleBuilderTest {
+
+ @Test
+ public void testModuleBuilder() {
+ final ModuleBuilder moduleBuilder = new ModuleBuilder();
+ final Module.Revision revision = new Module.Revision(new RevisionIdentifier("2016-10-11"));
+ final YangIdentifier yangIdentifierOne = new YangIdentifier("YangIdentifier1");
+ final YangIdentifier yangIdentifierTwo = new YangIdentifier("YangIdentifier2");
+ final Uri namespace = new Uri("namespace");
+ final Set<YangIdentifier> yangIdentifierList = ImmutableSet.of(yangIdentifierOne, yangIdentifierTwo);
+ final ModuleKey moduleKeyOne = new ModuleKey(yangIdentifierOne, revision);
+ final ModuleKey moduleKeyTwo = new ModuleKey(moduleKeyOne);
+ moduleBuilder.setRevision(revision);
+ moduleBuilder.setDeviation(yangIdentifierList);
+ moduleBuilder.setFeature(yangIdentifierList);
+ moduleBuilder.setName(yangIdentifierOne);
+ moduleBuilder.setNamespace(namespace);
+ moduleBuilder.withKey(moduleKeyOne);
+ final Module moduleOne = moduleBuilder.build();
+ final Module moduleTwo = new ModuleBuilder(moduleOne).build();
+
+ assertNotNull(moduleBuilder);
+ assertNotNull(revision);
+ assertNotNull(yangIdentifierOne);
+ assertNotNull(yangIdentifierTwo);
+ assertNotNull(namespace);
+ assertNotNull(yangIdentifierList);
+ assertNotNull(moduleKeyOne);
+ assertNotNull(moduleKeyOne.hashCode());
+ assertNotNull(moduleKeyOne.toString());
+ assertNotNull(moduleBuilder.toString());
+ assertNotNull(moduleBuilder.hashCode());
+
+ assertEquals(moduleKeyOne, moduleKeyTwo);
+ assertEquals(revision, moduleKeyOne.getRevision());
+ assertEquals(yangIdentifierOne, moduleKeyOne.getName());
+ assertEquals(revision, moduleBuilder.getRevision());
+ assertEquals(yangIdentifierList, moduleBuilder.getDeviation());
+ assertEquals(yangIdentifierList, moduleBuilder.getFeature());
+ assertEquals(yangIdentifierOne, moduleBuilder.getName());
+ assertEquals(namespace, moduleBuilder.getNamespace());
+ assertEquals(moduleKeyOne, moduleBuilder.key());
+ assertEquals(moduleOne.toString(), moduleTwo.toString());
+ assertEquals(moduleKeyOne.toString(), moduleKeyTwo.toString());
+
+ assertTrue(moduleOne.equals(moduleTwo));
+ assertTrue(moduleKeyOne.equals(moduleKeyTwo));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilderTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilderTest.java
new file mode 100644
index 0000000..578d2dd
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilderTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules.Module.Revision;
+
+public class ModuleRevisionBuilderTest {
+
+ @Test
+ public void testModuleRevisionBuilder() {
+ final ModuleRevisionBuilder moduleRevisionBuilder = new ModuleRevisionBuilder();
+ assertNotNull(moduleRevisionBuilder);
+ final Revision revision = ModuleRevisionBuilder.getDefaultInstance("");
+ assertNotNull(revision);
+ assertEquals("", revision.getString());
+ assertEquals(null, revision.getRevisionIdentifier());
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilderTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilderTest.java
new file mode 100644
index 0000000..5c2eba1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilderTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.RevisionIdentifier;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules.Module.Revision;
+
+public class RevisionBuilderTest {
+ @Test
+ public void testEmptyString() {
+ final RevisionBuilder revisionBuilder = new RevisionBuilder();
+ assertNotNull(revisionBuilder);
+ final Revision revision = RevisionBuilder.getDefaultInstance("");
+ validate(revision, "", null);
+ }
+
+ @Test
+ public void testValidDataString() {
+ final String dateString = "2014-04-23";
+ final Revision revision = RevisionBuilder.getDefaultInstance(dateString);
+ validate(revision, null, new RevisionIdentifier(dateString));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNullString() {
+ RevisionBuilder.getDefaultInstance(null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testBadFormatString() {
+ RevisionBuilder.getDefaultInstance("badFormat");
+ }
+
+ private static void validate(final Revision revisionUnderTest, final String expectedRevisionString,
+ final RevisionIdentifier expectedRevisionIdentifier) {
+ assertNotNull(revisionUnderTest);
+ assertEquals(expectedRevisionString, revisionUnderTest.getString());
+ assertEquals(expectedRevisionIdentifier, revisionUnderTest.getRevisionIdentifier());
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/json/dataa.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/json/dataa.json
new file mode 100644
index 0000000..6097bd1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/json/dataa.json
@@ -0,0 +1,7 @@
+{
+ "main:cont":{
+ "augment-main-a:cont1":{
+ "lf11":"lf11 value from a"
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/json/datab.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/json/datab.json
new file mode 100644
index 0000000..297584a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/json/datab.json
@@ -0,0 +1,7 @@
+{
+ "main:cont":{
+ "augment-main-b:cont1":{
+ "lf11":"lf11 value from b"
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/xml/dataa.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/xml/dataa.xml
new file mode 100644
index 0000000..97c5ae5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/xml/dataa.xml
@@ -0,0 +1,5 @@
+<cont xmlns="ns:main">
+ <cont1 xmlns="ns:augment:main:a">
+ <lf11>lf11 value for a</lf11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/xml/datab.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/xml/datab.xml
new file mode 100644
index 0000000..b7696ca
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/xml/datab.xml
@@ -0,0 +1,5 @@
+<cont xmlns="ns:main">
+ <cont1 xmlns="ns:augment:main:b">
+ <lf11>lf11 value for b</lf11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/augment-main-a.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/augment-main-a.yang
new file mode 100644
index 0000000..aa3bf3f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/augment-main-a.yang
@@ -0,0 +1,20 @@
+module augment-main-a {
+ namespace "ns:augment:main:a";
+ prefix "aumaa";
+
+
+ import main {prefix mn; revision-date 2014-01-21;}
+
+
+ revision "2014-01-21" {
+ }
+
+ augment "/mn:cont" {
+ container cont1 {
+ leaf lf11 {
+ type string;
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/augment-main-b.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/augment-main-b.yang
new file mode 100644
index 0000000..dcf493d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/augment-main-b.yang
@@ -0,0 +1,20 @@
+module augment-main-b {
+ namespace "ns:augment:main:b";
+ prefix "aumab";
+
+
+ import main {prefix mn; revision-date 2014-01-21;}
+
+
+ revision "2014-01-21" {
+ }
+
+ augment "/mn:cont" {
+ container cont1 {
+ leaf lf11 {
+ type string;
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/main.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/main.yang
new file mode 100644
index 0000000..e291722
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/common/augment/yang/main.yang
@@ -0,0 +1,10 @@
+module main {
+ namespace "ns:main";
+ prefix "ma";
+
+ revision "2014-01-21" {
+ }
+
+ container cont {
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/opendaylight-inventory.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/opendaylight-inventory.yang
new file mode 100644
index 0000000..e4247be
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/opendaylight-inventory.yang
@@ -0,0 +1,19 @@
+module opendaylight-inventory {
+ namespace "urn:opendaylight:inventory";
+ prefix inv;
+
+ revision "2013-08-19" {
+ description "Initial revision of Inventory model";
+ }
+
+
+ container nodes {
+ list node {
+ key "id";
+ leaf id {
+ type string;
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang
new file mode 100644
index 0000000..cdc8c69
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang
@@ -0,0 +1,39 @@
+module sal-remote-augment {
+
+ yang-version 1;
+ namespace "urn:sal:restconf:event:subscription";
+ prefix "salrmt-aug-ev-subscr";
+
+ import sal-remote {prefix salrmt; revision-date "2014-01-14";}
+
+ description
+ "Added input parameters to rpc create-data-change-event-subscription";
+
+ revision "2014-07-08" {
+ }
+
+ augment "/salrmt:create-data-change-event-subscription/salrmt:input" {
+ leaf datastore {
+ type enumeration {
+ enum OPERATIONAL;
+ enum CONFIGURATION;
+ }
+ }
+ leaf scope {
+ type enumeration {
+ enum BASE;
+ enum ONE;
+ enum SUBTREE;
+ }
+ }
+ leaf notification-output-type {
+ type enumeration {
+ enum JSON;
+ enum XML;
+ }
+ default "XML";
+ description "Input parameter which type of output will be parsed on notification";
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/sal-remote@2014-01-14.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/sal-remote@2014-01-14.yang
new file mode 100644
index 0000000..d12e252
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/datastore-and-scope-specification/sal-remote@2014-01-14.yang
@@ -0,0 +1,98 @@
+module sal-remote {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
+ prefix "sal-remote";
+
+
+ organization "Cisco Systems, Inc.";
+ contact "Martin Bobak <mbobak@cisco.com>";
+
+ description
+ "This module contains the definition of methods related to
+ sal remote model.
+
+ Copyright (c)2013 Cisco Systems, Inc. All rights reserved.
+
+ This program and the accompanying materials are made available
+ under the terms of the Eclipse Public License v1.0 which
+ accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html";
+
+ revision "2014-01-14" {
+ description
+ "Initial revision";
+ }
+
+
+ typedef q-name {
+ type string;
+ reference
+ "http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#QName";
+ }
+
+ rpc create-data-change-event-subscription {
+ input {
+ leaf path {
+ type instance-identifier;
+ description "Subtree path. ";
+ }
+ }
+ output {
+ leaf stream-name {
+ type string;
+ description "Notification stream name.";
+ }
+ }
+ }
+
+ notification data-changed-notification {
+ description "Data change notification.";
+ list data-change-event {
+ key path;
+ leaf path {
+ type instance-identifier;
+ }
+ leaf store {
+ type enumeration {
+ enum config;
+ enum operation;
+ }
+ }
+ leaf operation {
+ type enumeration {
+ enum created;
+ enum updated;
+ enum deleted;
+ }
+ }
+ anyxml data{
+ description "DataObject ";
+ }
+ }
+ }
+
+ rpc create-notification-stream {
+ input {
+ leaf-list notifications {
+ type q-name;
+ description "Notification QNames";
+ }
+ }
+ output {
+ leaf notification-stream-identifier {
+ type string;
+ description "Unique notification stream identifier, in which notifications will be propagated";
+ }
+ }
+ }
+
+ rpc begin-transaction{
+ output{
+ anyxml data-modification-transaction{
+ description "DataModificationTransaction xml";
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/decoding-exception/yang/number.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/decoding-exception/yang/number.yang
new file mode 100644
index 0000000..c463882
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/decoding-exception/yang/number.yang
@@ -0,0 +1,17 @@
+ module number {
+
+ namespace "number";
+ prefix "number";
+
+ revision 2014-04-24 {
+ }
+
+
+
+ container cont {
+ leaf lf {
+ type uint8;
+ }
+
+ }
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-container.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-container.json
new file mode 100644
index 0000000..78b097d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-container.json
@@ -0,0 +1,16 @@
+{
+ "cont":{
+ "cont1":[
+ {
+ "lst11":{
+ "lf111":"value1"
+ }
+ },
+ {
+ "lst11":{
+ "lf111":"value2"
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-container.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-container.xml
new file mode 100644
index 0000000..26a1f5f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-container.xml
@@ -0,0 +1,12 @@
+<cont>
+ <cont1>
+ <lst11>
+ <lf111>value1</lf111>
+ </lst11>
+ </cont1>
+ <cont1>
+ <lst11>
+ <lf111>value1</lf111>
+ </lst11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-leaf.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-leaf.json
new file mode 100644
index 0000000..d0a9fd4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-leaf.json
@@ -0,0 +1,15 @@
+{
+ "cont":{
+ "cont1":{
+ "lst11":[
+ {
+ "lf111":"value1",
+ "lf111":"value2"
+ },
+ {
+ "lf111":"value3"
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-leaf.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-leaf.xml
new file mode 100644
index 0000000..4221c2d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/equal-name-data-for-leaf.xml
@@ -0,0 +1,11 @@
+<cont>
+ <cont1>
+ <lst11>
+ <lf111>value1</lf111>,
+ <lf111>value2</lf111>,
+ </lst11>
+ <lst11>
+ <lf111>value3</lf111>,
+ </lst11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/yang/equal-data-node-names.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/yang/equal-data-node-names.yang
new file mode 100644
index 0000000..3a3653a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/equal-data-node-names/yang/equal-data-node-names.yang
@@ -0,0 +1,18 @@
+/* bug 1204 */
+module equal-data-node-names {
+ namespace "ns:equal:data:node:names";
+
+ prefix "eqdanona";
+ revision 2014-06-26 {
+ }
+
+ container cont {
+ container cont1 {
+ list lst11 {
+ leaf lf111 {
+ type string;
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/foo-xml-test/foo.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/foo-xml-test/foo.xml
new file mode 100644
index 0000000..96b69c4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/foo-xml-test/foo.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<top-level-list xmlns="foo">
+ <key-leaf>key-value</key-leaf>
+ <ordinary-leaf>leaf-value</ordinary-leaf>
+</top-level-list> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/foo-xml-test/yang/foo.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/foo-xml-test/yang/foo.yang
new file mode 100644
index 0000000..ceed3d9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/foo-xml-test/yang/foo.yang
@@ -0,0 +1,18 @@
+module foo {
+ namespace foo;
+ prefix foo;
+
+ revision 2017-08-09;
+
+ list top-level-list {
+ key key-leaf;
+
+ leaf key-leaf {
+ type string;
+ }
+
+ leaf ordinary-leaf {
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/make-toast-rpc-input.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/make-toast-rpc-input.json
new file mode 100644
index 0000000..1bba146
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/make-toast-rpc-input.json
@@ -0,0 +1,7 @@
+{
+ "input" :
+ {
+ "toaster:toasterDoneness" : "10",
+ "toaster:toasterToastType": "wheat-bread"
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data-rpc-input.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data-rpc-input.json
new file mode 100644
index 0000000..0eae37a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data-rpc-input.json
@@ -0,0 +1,10 @@
+{
+ "test-module:input":{
+ "cont":{
+ "cont1":{
+ "lf11":"lf1 data",
+ "lf12":"lf2 data"
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data-rpc-input.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data-rpc-input.xml
new file mode 100644
index 0000000..fb9726d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data-rpc-input.xml
@@ -0,0 +1,8 @@
+<input xmlns="test:module">
+ <cont>
+ <cont1>
+ <lf11>lf1 data</lf11>
+ <lf12>lf2 data</lf12>
+ </cont1>
+ </cont>
+</input> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data2.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data2.xml
new file mode 100644
index 0000000..db2f4e9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data2.xml
@@ -0,0 +1,6 @@
+<cont xmlns="test:module">
+ <cont1>
+ <lf11>lf1 data</lf11>
+ <lf12>lf2 data</lf12>
+ </cont1>
+</cont>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data3.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data3.xml
new file mode 100644
index 0000000..b7b05d1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data3.xml
@@ -0,0 +1,4 @@
+<cont1 xmlns="test:module">
+ <lf11>lf1 data</lf11>
+ <lf12>lf2 data</lf12>
+</cont1>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data4.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data4.xml
new file mode 100644
index 0000000..3ce6741
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data4.xml
@@ -0,0 +1,6 @@
+
+<cont1 xmlns="test:module">
+ <lf11>lf1 data</lf11>
+ <lf12>lf2 data</lf12>
+</cont1>
+
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data5.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data5.xml
new file mode 100644
index 0000000..89aa782
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data5.xml
@@ -0,0 +1,8 @@
+<interfaces xmlns="test:module">
+ <class>
+ <name>John</name>
+ <address>F.C.I 43</address>
+ <email>j@j</email>
+ </class>
+</interfaces>
+
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data6.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data6.xml
new file mode 100644
index 0000000..7feb6bf
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data6.xml
@@ -0,0 +1,6 @@
+<class xmlns="test:module">
+ <name>John</name>
+ <address>F.C.I 43</address>
+ <email>j@j</email>
+</class>
+
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data7.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data7.xml
new file mode 100644
index 0000000..4374277
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-data2/data7.xml
@@ -0,0 +1,8 @@
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <cont xmlns="test:module">
+ <cont1>
+ <lf11>lf1 data</lf11>
+ <lf12>lf2 data</lf12>
+ </cont1>
+ </cont>
+</data> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-module/test-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-module/test-module.yang
new file mode 100644
index 0000000..2cc78b3
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/test-module/test-module.yang
@@ -0,0 +1,101 @@
+module test-module {
+ namespace "test:module";
+ prefix tstmod;
+
+ revision 2014-01-09 {
+ }
+
+ identity module-type {
+ }
+
+ identity test-identity {
+ }
+
+ container interfaces {
+ container class {
+ leaf name {
+ type string;
+ }
+ leaf address {
+ type string;
+ }
+ leaf email {
+ type string;
+ }
+ }
+ }
+
+ container cont {
+ container cont1 {
+ leaf lf11 {
+ type string;
+ }
+ leaf lf12 {
+ type string;
+ }
+ }
+ list lst1 {
+ key "lf11";
+ leaf lf11 {
+ type string;
+ }
+ }
+ }
+
+ container modules {
+ list module {
+ key "type name";
+ leaf name {
+ type string;
+ mandatory true;
+ }
+
+ leaf type {
+ type identityref {
+ base module-type;
+ }
+ mandatory true;
+ }
+
+ leaf data {
+ type string;
+ }
+ }
+ }
+
+ list lst-with-composite-key {
+ key "key1 key2";
+ leaf key1 {
+ type string;
+ }
+ leaf key2 {
+ type uint8;
+ }
+ }
+
+ rpc no-payload-rpc-test {
+ output {
+ container cont-output {
+ }
+ }
+ }
+
+ rpc rpc-test {
+ input {
+ container cont {
+ container cont1 {
+ leaf lf11 {
+ type string;
+ }
+ leaf lf12 {
+ type string;
+ }
+ }
+ }
+ }
+ output {
+ container cont-output {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testCont1Data.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testCont1Data.json
new file mode 100644
index 0000000..c7554f7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testCont1Data.json
@@ -0,0 +1,6 @@
+{
+ "cont1": {
+ "lf11": "lf11 data",
+ "lf12": "lf12 data"
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testCont1DataPatch.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testCont1DataPatch.json
new file mode 100644
index 0000000..a8d6799
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testCont1DataPatch.json
@@ -0,0 +1,20 @@
+{
+ "ietf-restconf:yang-patch" : {
+ "patch-id" : "0",
+ "edit" : [
+ {
+ "edit-id" : "edit1",
+ "operation" : "create",
+ "target" : "",
+ "value" :
+ {
+ "cont1":
+ {
+ "lf11": "lf11 data",
+ "lf12": "lf12 data"
+ }
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testData.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testData.json
new file mode 100644
index 0000000..a736067
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testData.json
@@ -0,0 +1,92 @@
+{
+ "interfaces": {
+ "interface": [
+ {
+ "name": "eth0",
+ "type": "ethernetCsmacd",
+ "enabled": false
+ },
+ {
+ "name": "eth1",
+ "type": "ethernetCsmacd",
+ "enabled": true,
+ "vlan-tagging": true
+ },
+ {
+ "name": "eth1.10",
+ "type": "l2vlan",
+ "enabled": true,
+ "base-interface": "eth1",
+ "vlan-id": 10
+ },
+ {
+ "name": "lo1",
+ "type": "softwareLoopback",
+ "enabled": true
+ }
+ ]
+ },
+ "interfaces-state": {
+ "interface": [
+ {
+ "name": "eth0",
+ "type": "ethernetCsmacd",
+ "admin-status": "down",
+ "oper-status": "down",
+ "if-index": 2,
+ "phys-address": "00:01:02:03:04:05",
+ "statistics": {
+ "discontinuity-time": "2013-04-01T03:00:00+00:00"
+ }
+ },
+ {
+ "name": "eth1",
+ "type": "ethernetCsmacd",
+ "admin-status": "up",
+ "oper-status": "up",
+ "if-index": 7,
+ "phys-address": "00:01:02:03:04:06",
+ "higher-layer-if": [
+ "eth1.10"
+ ],
+ "statistics": {
+ "discontinuity-time": "2013-04-01T03:00:00+00:00"
+ }
+ },
+ {
+ "name": "eth1.10",
+ "type": "l2vlan",
+ "admin-status": "up",
+ "oper-status": "up",
+ "if-index": 9,
+ "lower-layer-if": [
+ "eth1"
+ ],
+ "statistics": {
+ "discontinuity-time": "2013-04-01T03:00:00+00:00"
+ }
+ },
+ {
+ "name": "eth2",
+ "type": "ethernetCsmacd",
+ "admin-status": "down",
+ "oper-status": "down",
+ "if-index": 8,
+ "phys-address": "00:01:02:03:04:07",
+ "statistics": {
+ "discontinuity-time": "2013-04-01T03:00:00+00:00"
+ }
+ },
+ {
+ "name": "lo1",
+ "type": "softwareLoopback",
+ "admin-status": "up",
+ "oper-status": "up",
+ "if-index": 1,
+ "statistics": {
+ "discontinuity-time": "2013-04-01T03:00:00+00:00"
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testData.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testData.xml
new file mode 100644
index 0000000..bdd9c10
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/testData.xml
@@ -0,0 +1,120 @@
+<rpc-reply
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
+ message-id="101">
+ <data>
+
+ <interfaces
+ xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"
+ xmlns:vlan="http://example.com/vlan">
+
+ <interface>
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+ </interface>
+
+ <interface>
+ <name>eth1</name>
+ <type>ethernetCsmacd</type>
+ <enabled>true</enabled>
+ <vlan:vlan-tagging>true</vlan:vlan-tagging>
+ </interface>
+
+ <interface>
+ <name>eth1.10</name>
+ <type>l2vlan</type>
+ <enabled>true</enabled>
+ <vlan:base-interface>eth1</vlan:base-interface>
+ <vlan:vlan-id>10</vlan:vlan-id>
+ </interface>
+
+ <interface>
+ <name>lo1</name>
+ <type>softwareLoopback</type>
+ <enabled>true</enabled>
+ </interface>
+
+ </interfaces>
+
+ <interfaces-state
+ xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
+
+ <interface>
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <admin-status>down</admin-status>
+ <oper-status>down</oper-status>
+ <if-index>2</if-index>
+ <phys-address>00:01:02:03:04:05</phys-address>
+ <statistics>
+ <discontinuity-time>
+ 2013-04-01T03:00:00+00:00
+ </discontinuity-time>
+ <!-- counters now shown here -->
+ </statistics>
+ </interface>
+
+ <interface>
+ <name>eth1</name>
+ <type>ethernetCsmacd</type>
+ <admin-status>up</admin-status>
+ <oper-status>up</oper-status>
+ <if-index>7</if-index>
+ <phys-address>00:01:02:03:04:06</phys-address>
+ <higher-layer-if>eth1.10</higher-layer-if>
+ <statistics>
+ <discontinuity-time>
+ 2013-04-01T03:00:00+00:00
+ </discontinuity-time>
+ <!-- counters now shown here -->
+ </statistics>
+ </interface>
+
+ <interface>
+ <name>eth1.10</name>
+ <type>l2vlan</type>
+ <admin-status>up</admin-status>
+ <oper-status>up</oper-status>
+ <if-index>9</if-index>
+ <lower-layer-if>eth1</lower-layer-if>
+ <statistics>
+ <discontinuity-time>
+ 2013-04-01T03:00:00+00:00
+ </discontinuity-time>
+ <!-- counters now shown here -->
+ </statistics>
+ </interface>
+
+ <!-- This interface is not configured -->
+ <interface>
+ <name>eth2</name>
+ <type>ethernetCsmacd</type>
+ <admin-status>down</admin-status>
+ <oper-status>down</oper-status>
+ <if-index>8</if-index>
+ <phys-address>00:01:02:03:04:07</phys-address>
+ <statistics>
+ <discontinuity-time>
+ 2013-04-01T03:00:00+00:00
+ </discontinuity-time>
+ <!-- counters now shown here -->
+ </statistics>
+ </interface>
+
+ <interface>
+ <name>lo1</name>
+ <type>softwareLoopback</type>
+ <admin-status>up</admin-status>
+ <oper-status>up</oper-status>
+ <if-index>1</if-index>
+ <statistics>
+ <discontinuity-time>
+ 2013-04-01T03:00:00+00:00
+ </discontinuity-time>
+ <!-- counters now shown here -->
+ </statistics>
+ </interface>
+
+ </interfaces-state>
+ </data>
+</rpc-reply> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ex-vlan.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ex-vlan.yang
new file mode 100644
index 0000000..59369ad
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ex-vlan.yang
@@ -0,0 +1,47 @@
+module ex-vlan {
+ namespace "http://example.com/vlan";
+ prefix "vlan";
+
+ import ietf-interfaces {
+ prefix if;
+ }
+
+ revision 2013-10-22 {
+ description
+ "Initial revision.";
+ reference
+ "RFC A YANG Data Model for Interface Management draft-ietf-netmod-interfaces-cfg-12 - Appendix C";
+ }
+
+ augment "/if:interfaces/if:interface" {
+ when "if:type = 'ethernetCsmacd' or
+ if:type = 'ieee8023adLag'";
+ leaf vlan-tagging {
+ type boolean;
+ default false;
+ }
+ }
+
+ augment "/if:interfaces/if:interface" {
+ when "if:type = 'l2vlan'";
+
+ leaf base-interface {
+ type if:interface-ref;
+ must "/if:interfaces/if:interface[if:name = current()]"
+ + "/vlan:vlan-tagging = 'true'" {
+ description
+ "The base interface must have vlan tagging enabled.";
+ }
+ }
+ leaf vlan-id {
+ type uint16 {
+ range "1..4094";
+ }
+ must "../base-interface" {
+ description
+ "If a vlan-id is defined, a base-interface must
+ be specified.";
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/iana-if-type.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/iana-if-type.yang
new file mode 100644
index 0000000..7bd0003
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/iana-if-type.yang
@@ -0,0 +1,1517 @@
+module iana-if-type {
+ namespace "urn:ietf:params:xml:ns:yang:iana-if-type";
+ prefix ianaift;
+
+ organization "IANA";
+ contact
+ " Internet Assigned Numbers Authority
+
+ Postal: ICANN
+ 4676 Admiralty Way, Suite 330
+ Marina del Rey, CA 90292
+
+ Tel: +1 310 823 9358
+ E-Mail: iana&iana.org";
+ description
+ "This YANG module defines the iana-if-type typedef, which
+ contains YANG definitions for IANA-registered interface types.
+
+ This YANG module is maintained by IANA, and reflects the
+ 'ifType definitions' registry.
+
+ The latest revision of this YANG module can be obtained from
+ the IANA web site.
+
+ Copyright (c) 2011 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-07-04 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: IANA Interface Type YANG Module";
+ }
+
+ typedef iana-if-type {
+ type enumeration {
+ enum "other" {
+ value 1;
+ description
+ "None of the following";
+ }
+ enum "regular1822" {
+ value 2;
+ }
+ enum "hdh1822" {
+ value 3;
+ }
+ enum "ddnX25" {
+ value 4;
+ }
+ enum "rfc877x25" {
+ value 5;
+ reference
+ "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer";
+ }
+ enum "ethernetCsmacd" {
+ value 6;
+ description
+ "For all ethernet-like interfaces, regardless of speed,
+ as per RFC3635.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "iso88023Csmacd" {
+ value 7;
+ status deprecated;
+ description
+ "Deprecated via RFC3635.
+ Use ethernetCsmacd(6) instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "iso88024TokenBus" {
+ value 8;
+ }
+ enum "iso88025TokenRing" {
+ value 9;
+ }
+ enum "iso88026Man" {
+ value 10;
+ }
+ enum "starLan" {
+ value 11;
+ status deprecated;
+ description
+ "Deprecated via RFC3635.
+ Use ethernetCsmacd(6) instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "proteon10Mbit" {
+ value 12;
+ }
+ enum "proteon80Mbit" {
+ value 13;
+ }
+ enum "hyperchannel" {
+ value 14;
+ }
+ enum "fddi" {
+ value 15;
+ reference
+ "RFC 1512 - FDDI Management Information Base";
+ }
+ enum "lapb" {
+ value 16;
+ reference
+ "RFC 1381 - SNMP MIB Extension for X.25 LAPB";
+ }
+ enum "sdlc" {
+ value 17;
+ }
+ enum "ds1" {
+ value 18;
+ description
+ "DS1-MIB";
+ reference
+ "RFC 4805 - Definitions of Managed Objects for the
+ DS1, J1, E1, DS2, and E2 Interface Types";
+ }
+ enum "e1" {
+ value 19;
+ status obsolete;
+ description
+ "Obsolete see DS1-MIB";
+ reference
+ "RFC 4805 - Definitions of Managed Objects for the
+ DS1, J1, E1, DS2, and E2 Interface Types";
+ }
+ enum "basicISDN" {
+ value 20;
+ description
+ "see also RFC2127";
+ }
+ enum "primaryISDN" {
+ value 21;
+ }
+ enum "propPointToPointSerial" {
+ value 22;
+ description
+ "proprietary serial";
+ }
+ enum "ppp" {
+ value 23;
+ }
+ enum "softwareLoopback" {
+ value 24;
+ }
+ enum "eon" {
+ value 25;
+ description
+ "CLNP over IP";
+ }
+ enum "ethernet3Mbit" {
+ value 26;
+ }
+ enum "nsip" {
+ value 27;
+ description
+ "XNS over IP";
+ }
+ enum "slip" {
+ value 28;
+ description
+ "generic SLIP";
+ }
+ enum "ultra" {
+ value 29;
+ description
+ "ULTRA technologies";
+ }
+ enum "ds3" {
+ value 30;
+ description
+ "DS3-MIB";
+ reference
+ "RFC 3896 - Definitions of Managed Objects for the
+ DS3/E3 Interface Type";
+ }
+ enum "sip" {
+ value 31;
+ description
+ "SMDS, coffee";
+ reference
+ "RFC 1694 - Definitions of Managed Objects for SMDS
+ Interfaces using SMIv2";
+ }
+ enum "frameRelay" {
+ value 32;
+ description
+ "DTE only.";
+ reference
+ "RFC 2115 - Management Information Base for Frame Relay
+ DTEs Using SMIv2";
+ }
+ enum "rs232" {
+ value 33;
+ reference
+ "RFC 1659 - Definitions of Managed Objects for RS-232-like
+ Hardware Devices using SMIv2";
+ }
+ enum "para" {
+ value 34;
+ description
+ "parallel-port";
+ reference
+ "RFC 1660 - Definitions of Managed Objects for
+ Parallel-printer-like Hardware Devices using
+ SMIv2";
+ }
+ enum "arcnet" {
+ value 35;
+ description
+ "arcnet";
+ }
+ enum "arcnetPlus" {
+ value 36;
+ description
+ "arcnet plus";
+ }
+ enum "atm" {
+ value 37;
+ description
+ "ATM cells";
+ }
+ enum "miox25" {
+ value 38;
+ reference
+ "RFC 1461 - SNMP MIB extension for Multiprotocol
+ Interconnect over X.25";
+ }
+ enum "sonet" {
+ value 39;
+ description
+ "SONET or SDH";
+ }
+ enum "x25ple" {
+ value 40;
+ reference
+ "RFC 2127 - ISDN Management Information Base using SMIv2";
+ }
+ enum "iso88022llc" {
+ value 41;
+ }
+ enum "localTalk" {
+ value 42;
+ }
+ enum "smdsDxi" {
+ value 43;
+ }
+ enum "frameRelayService" {
+ value 44;
+ description
+ "FRNETSERV-MIB";
+ reference
+ "RFC 2954 - Definitions of Managed Objects for Frame
+ Relay Service";
+ }
+ enum "v35" {
+ value 45;
+ }
+ enum "hssi" {
+ value 46;
+ }
+ enum "hippi" {
+ value 47;
+ }
+ enum "modem" {
+ value 48;
+ description
+ "Generic modem";
+ }
+ enum "aal5" {
+ value 49;
+ description
+ "AAL5 over ATM";
+ }
+ enum "sonetPath" {
+ value 50;
+ }
+ enum "sonetVT" {
+ value 51;
+ }
+ enum "smdsIcip" {
+ value 52;
+ description
+ "SMDS InterCarrier Interface";
+ }
+ enum "propVirtual" {
+ value 53;
+ description
+ "proprietary virtual/internal";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+ enum "propMultiplexor" {
+ value 54;
+ description
+ "proprietary multiplexing";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+ enum "ieee80212" {
+ value 55;
+ description
+ "100BaseVG";
+ }
+ enum "fibreChannel" {
+ value 56;
+ description
+ "Fibre Channel";
+ }
+ enum "hippiInterface" {
+ value 57;
+ description
+ "HIPPI interfaces";
+ }
+ enum "frameRelayInterconnect" {
+ value 58;
+ status obsolete;
+ description
+ "Obsolete use either
+ frameRelay(32) or frameRelayService(44).";
+ }
+ enum "aflane8023" {
+ value 59;
+ description
+ "ATM Emulated LAN for 802.3";
+ }
+ enum "aflane8025" {
+ value 60;
+ description
+ "ATM Emulated LAN for 802.5";
+ }
+ enum "cctEmul" {
+ value 61;
+ description
+ "ATM Emulated circuit";
+ }
+ enum "fastEther" {
+ value 62;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635.
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "isdn" {
+ value 63;
+ description
+ "ISDN and X.25";
+ reference
+ "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN
+ in the Packet Mode";
+ }
+ enum "v11" {
+ value 64;
+ description
+ "CCITT V.11/X.21";
+ }
+ enum "v36" {
+ value 65;
+ description
+ "CCITT V.36";
+ }
+ enum "g703at64k" {
+ value 66;
+ description
+ "CCITT G703 at 64Kbps";
+ }
+ enum "g703at2mb" {
+ value 67;
+ status obsolete;
+ description
+ "Obsolete see DS1-MIB";
+ }
+ enum "qllc" {
+ value 68;
+ description
+ "SNA QLLC";
+ }
+ enum "fastEtherFX" {
+ value 69;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "channel" {
+ value 70;
+ description
+ "channel";
+ }
+ enum "ieee80211" {
+ value 71;
+ description
+ "radio spread spectrum";
+ }
+ enum "ibm370parChan" {
+ value 72;
+ description
+ "IBM System 360/370 OEMI Channel";
+ }
+ enum "escon" {
+ value 73;
+ description
+ "IBM Enterprise Systems Connection";
+ }
+ enum "dlsw" {
+ value 74;
+ description
+ "Data Link Switching";
+ }
+ enum "isdns" {
+ value 75;
+ description
+ "ISDN S/T interface";
+ }
+ enum "isdnu" {
+ value 76;
+ description
+ "ISDN U interface";
+ }
+ enum "lapd" {
+ value 77;
+ description
+ "Link Access Protocol D";
+ }
+ enum "ipSwitch" {
+ value 78;
+ description
+ "IP Switching Objects";
+ }
+ enum "rsrb" {
+ value 79;
+ description
+ "Remote Source Route Bridging";
+ }
+ enum "atmLogical" {
+ value 80;
+ description
+ "ATM Logical Port";
+ reference
+ "RFC 3606 - Definitions of Supplemental Managed Objects
+ for ATM Interface";
+ }
+ enum "ds0" {
+ value 81;
+ description
+ "Digital Signal Level 0";
+ reference
+ "RFC 2494 - Definitions of Managed Objects for the DS0
+ and DS0 Bundle Interface Type";
+ }
+ enum "ds0Bundle" {
+ value 82;
+ description
+ "group of ds0s on the same ds1";
+ reference
+ "RFC 2494 - Definitions of Managed Objects for the DS0
+ and DS0 Bundle Interface Type";
+ }
+ enum "bsc" {
+ value 83;
+ description
+ "Bisynchronous Protocol";
+ }
+ enum "async" {
+ value 84;
+ description
+ "Asynchronous Protocol";
+ }
+ enum "cnr" {
+ value 85;
+ description
+ "Combat Net Radio";
+ }
+ enum "iso88025Dtr" {
+ value 86;
+ description
+ "ISO 802.5r DTR";
+ }
+ enum "eplrs" {
+ value 87;
+ description
+ "Ext Pos Loc Report Sys";
+ }
+ enum "arap" {
+ value 88;
+ description
+ "Appletalk Remote Access Protocol";
+ }
+ enum "propCnls" {
+ value 89;
+ description
+ "Proprietary Connectionless Protocol";
+ }
+ enum "hostPad" {
+ value 90;
+ description
+ "CCITT-ITU X.29 PAD Protocol";
+ }
+ enum "termPad" {
+ value 91;
+ description
+ "CCITT-ITU X.3 PAD Facility";
+ }
+ enum "frameRelayMPI" {
+ value 92;
+ description
+ "Multiproto Interconnect over FR";
+ }
+ enum "x213" {
+ value 93;
+ description
+ "CCITT-ITU X213";
+ }
+ enum "adsl" {
+ value 94;
+ description
+ "Asymmetric Digital Subscriber Loop";
+ }
+ enum "radsl" {
+ value 95;
+ description
+ "Rate-Adapt. Digital Subscriber Loop";
+ }
+ enum "sdsl" {
+ value 96;
+ description
+ "Symmetric Digital Subscriber Loop";
+ }
+ enum "vdsl" {
+ value 97;
+ description
+ "Very H-Speed Digital Subscrib. Loop";
+ }
+ enum "iso88025CRFPInt" {
+ value 98;
+ description
+ "ISO 802.5 CRFP";
+ }
+ enum "myrinet" {
+ value 99;
+ description
+ "Myricom Myrinet";
+ }
+ enum "voiceEM" {
+ value 100;
+ description
+ "voice recEive and transMit";
+ }
+ enum "voiceFXO" {
+ value 101;
+ description
+ "voice Foreign Exchange Office";
+ }
+ enum "voiceFXS" {
+ value 102;
+ description
+ "voice Foreign Exchange Station";
+ }
+ enum "voiceEncap" {
+ value 103;
+ description
+ "voice encapsulation";
+ }
+ enum "voiceOverIp" {
+ value 104;
+ description
+ "voice over IP encapsulation";
+ }
+ enum "atmDxi" {
+ value 105;
+ description
+ "ATM DXI";
+ }
+ enum "atmFuni" {
+ value 106;
+ description
+ "ATM FUNI";
+ }
+ enum "atmIma" {
+ value 107;
+ description
+ "ATM IMA";
+ }
+ enum "pppMultilinkBundle" {
+ value 108;
+ description
+ "PPP Multilink Bundle";
+ }
+ enum "ipOverCdlc" {
+ value 109;
+ description
+ "IBM ipOverCdlc";
+ }
+ enum "ipOverClaw" {
+ value 110;
+ description
+ "IBM Common Link Access to Workstn";
+ }
+ enum "stackToStack" {
+ value 111;
+ description
+ "IBM stackToStack";
+ }
+ enum "virtualIpAddress" {
+ value 112;
+ description
+ "IBM VIPA";
+ }
+ enum "mpc" {
+ value 113;
+ description
+ "IBM multi-protocol channel support";
+ }
+ enum "ipOverAtm" {
+ value 114;
+ description
+ "IBM ipOverAtm";
+ reference
+ "RFC 2320 - Definitions of Managed Objects for Classical IP
+ and ARP Over ATM Using SMIv2 (IPOA-MIB)";
+ }
+ enum "iso88025Fiber" {
+ value 115;
+ description
+ "ISO 802.5j Fiber Token Ring";
+ }
+ enum "tdlc" {
+ value 116;
+ description
+ "IBM twinaxial data link control";
+ }
+ enum "gigabitEthernet" {
+ value 117;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "hdlc" {
+ value 118;
+ description
+ "HDLC";
+ }
+ enum "lapf" {
+ value 119;
+ description
+ "LAP F";
+ }
+ enum "v37" {
+ value 120;
+ description
+ "V.37";
+ }
+ enum "x25mlp" {
+ value 121;
+ description
+ "Multi-Link Protocol";
+ }
+ enum "x25huntGroup" {
+ value 122;
+ description
+ "X25 Hunt Group";
+ }
+ enum "transpHdlc" {
+ value 123;
+ description
+ "Transp HDLC";
+ }
+ enum "interleave" {
+ value 124;
+ description
+ "Interleave channel";
+ }
+ enum "fast" {
+ value 125;
+ description
+ "Fast channel";
+ }
+ enum "ip" {
+ value 126;
+ description
+ "IP (for APPN HPR in IP networks)";
+ }
+ enum "docsCableMaclayer" {
+ value 127;
+ description
+ "CATV Mac Layer";
+ }
+ enum "docsCableDownstream" {
+ value 128;
+ description
+ "CATV Downstream interface";
+ }
+ enum "docsCableUpstream" {
+ value 129;
+ description
+ "CATV Upstream interface";
+ }
+ enum "a12MppSwitch" {
+ value 130;
+ description
+ "Avalon Parallel Processor";
+ }
+ enum "tunnel" {
+ value 131;
+ description
+ "Encapsulation interface";
+ }
+ enum "coffee" {
+ value 132;
+ description
+ "coffee pot";
+ reference
+ "RFC 2325 - Coffee MIB";
+ }
+ enum "ces" {
+ value 133;
+ description
+ "Circuit Emulation Service";
+ }
+ enum "atmSubInterface" {
+ value 134;
+ description
+ "ATM Sub Interface";
+ }
+ enum "l2vlan" {
+ value 135;
+ description
+ "Layer 2 Virtual LAN using 802.1Q";
+ }
+ enum "l3ipvlan" {
+ value 136;
+ description
+ "Layer 3 Virtual LAN using IP";
+ }
+ enum "l3ipxvlan" {
+ value 137;
+ description
+ "Layer 3 Virtual LAN using IPX";
+ }
+ enum "digitalPowerline" {
+ value 138;
+ description
+ "IP over Power Lines";
+ }
+ enum "mediaMailOverIp" {
+ value 139;
+ description
+ "Multimedia Mail over IP";
+ }
+ enum "dtm" {
+ value 140;
+ description
+ "Dynamic syncronous Transfer Mode";
+ }
+ enum "dcn" {
+ value 141;
+ description
+ "Data Communications Network";
+ }
+ enum "ipForward" {
+ value 142;
+ description
+ "IP Forwarding Interface";
+ }
+ enum "msdsl" {
+ value 143;
+ description
+ "Multi-rate Symmetric DSL";
+ }
+ enum "ieee1394" {
+ value 144;
+ description
+ "IEEE1394 High Performance Serial Bus";
+ }
+ enum "if-gsn" {
+ value 145;
+ description
+ "HIPPI-6400";
+ }
+ enum "dvbRccMacLayer" {
+ value 146;
+ description
+ "DVB-RCC MAC Layer";
+ }
+ enum "dvbRccDownstream" {
+ value 147;
+ description
+ "DVB-RCC Downstream Channel";
+ }
+ enum "dvbRccUpstream" {
+ value 148;
+ description
+ "DVB-RCC Upstream Channel";
+ }
+ enum "atmVirtual" {
+ value 149;
+ description
+ "ATM Virtual Interface";
+ }
+ enum "mplsTunnel" {
+ value 150;
+ description
+ "MPLS Tunnel Virtual Interface";
+ }
+ enum "srp" {
+ value 151;
+ description
+ "Spatial Reuse Protocol";
+ }
+ enum "voiceOverAtm" {
+ value 152;
+ description
+ "Voice Over ATM";
+ }
+ enum "voiceOverFrameRelay" {
+ value 153;
+ description
+ "Voice Over Frame Relay";
+ }
+ enum "idsl" {
+ value 154;
+ description
+ "Digital Subscriber Loop over ISDN";
+ }
+ enum "compositeLink" {
+ value 155;
+ description
+ "Avici Composite Link Interface";
+ }
+ enum "ss7SigLink" {
+ value 156;
+ description
+ "SS7 Signaling Link";
+ }
+ enum "propWirelessP2P" {
+ value 157;
+ description
+ "Prop. P2P wireless interface";
+ }
+ enum "frForward" {
+ value 158;
+ description
+ "Frame Forward Interface";
+ }
+ enum "rfc1483" {
+ value 159;
+ description
+ "Multiprotocol over ATM AAL5";
+ reference
+ "RFC 1483 - Multiprotocol Encapsulation over ATM
+ Adaptation Layer 5";
+ }
+ enum "usb" {
+ value 160;
+ description
+ "USB Interface";
+ }
+ enum "ieee8023adLag" {
+ value 161;
+ description
+ "IEEE 802.3ad Link Aggregate";
+ }
+ enum "bgppolicyaccounting" {
+ value 162;
+ description
+ "BGP Policy Accounting";
+ }
+ enum "frf16MfrBundle" {
+ value 163;
+ description
+ "FRF .16 Multilink Frame Relay";
+ }
+ enum "h323Gatekeeper" {
+ value 164;
+ description
+ "H323 Gatekeeper";
+ }
+ enum "h323Proxy" {
+ value 165;
+ description
+ "H323 Voice and Video Proxy";
+ }
+ enum "mpls" {
+ value 166;
+ description
+ "MPLS";
+ }
+ enum "mfSigLink" {
+ value 167;
+ description
+ "Multi-frequency signaling link";
+ }
+ enum "hdsl2" {
+ value 168;
+ description
+ "High Bit-Rate DSL - 2nd generation";
+ }
+ enum "shdsl" {
+ value 169;
+ description
+ "Multirate HDSL2";
+ }
+ enum "ds1FDL" {
+ value 170;
+ description
+ "Facility Data Link 4Kbps on a DS1";
+ }
+ enum "pos" {
+ value 171;
+ description
+ "Packet over SONET/SDH Interface";
+ }
+ enum "dvbAsiIn" {
+ value 172;
+ description
+ "DVB-ASI Input";
+ }
+ enum "dvbAsiOut" {
+ value 173;
+ description
+ "DVB-ASI Output";
+ }
+ enum "plc" {
+ value 174;
+ description
+ "Power Line Communtications";
+ }
+ enum "nfas" {
+ value 175;
+ description
+ "Non Facility Associated Signaling";
+ }
+ enum "tr008" {
+ value 176;
+ description
+ "TR008";
+ }
+ enum "gr303RDT" {
+ value 177;
+ description
+ "Remote Digital Terminal";
+ }
+ enum "gr303IDT" {
+ value 178;
+ description
+ "Integrated Digital Terminal";
+ }
+ enum "isup" {
+ value 179;
+ description
+ "ISUP";
+ }
+ enum "propDocsWirelessMaclayer" {
+ value 180;
+ description
+ "Cisco proprietary Maclayer";
+ }
+ enum "propDocsWirelessDownstream" {
+ value 181;
+ description
+ "Cisco proprietary Downstream";
+ }
+ enum "propDocsWirelessUpstream" {
+ value 182;
+ description
+ "Cisco proprietary Upstream";
+ }
+ enum "hiperlan2" {
+ value 183;
+ description
+ "HIPERLAN Type 2 Radio Interface";
+ }
+ enum "propBWAp2Mp" {
+ value 184;
+ description
+ "PropBroadbandWirelessAccesspt2multipt use of this value
+ for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f
+ is deprecated and ieee80216WMAN(237) should be used
+ instead.";
+ }
+ enum "sonetOverheadChannel" {
+ value 185;
+ description
+ "SONET Overhead Channel";
+ }
+ enum "digitalWrapperOverheadChannel" {
+ value 186;
+ description
+ "Digital Wrapper";
+ }
+ enum "aal2" {
+ value 187;
+ description
+ "ATM adaptation layer 2";
+ }
+ enum "radioMAC" {
+ value 188;
+ description
+ "MAC layer over radio links";
+ }
+ enum "atmRadio" {
+ value 189;
+ description
+ "ATM over radio links";
+ }
+ enum "imt" {
+ value 190;
+ description
+ "Inter Machine Trunks";
+ }
+ enum "mvl" {
+ value 191;
+ description
+ "Multiple Virtual Lines DSL";
+ }
+ enum "reachDSL" {
+ value 192;
+ description
+ "Long Reach DSL";
+ }
+ enum "frDlciEndPt" {
+ value 193;
+ description
+ "Frame Relay DLCI End Point";
+ }
+ enum "atmVciEndPt" {
+ value 194;
+ description
+ "ATM VCI End Point";
+ }
+ enum "opticalChannel" {
+ value 195;
+ description
+ "Optical Channel";
+ }
+ enum "opticalTransport" {
+ value 196;
+ description
+ "Optical Transport";
+ }
+ enum "propAtm" {
+ value 197;
+ description
+ "Proprietary ATM";
+ }
+ enum "voiceOverCable" {
+ value 198;
+ description
+ "Voice Over Cable Interface";
+ }
+ enum "infiniband" {
+ value 199;
+ description
+ "Infiniband";
+ }
+ enum "teLink" {
+ value 200;
+ description
+ "TE Link";
+ }
+ enum "q2931" {
+ value 201;
+ description
+ "Q.2931";
+ }
+ enum "virtualTg" {
+ value 202;
+ description
+ "Virtual Trunk Group";
+ }
+ enum "sipTg" {
+ value 203;
+ description
+ "SIP Trunk Group";
+ }
+ enum "sipSig" {
+ value 204;
+ description
+ "SIP Signaling";
+ }
+ enum "docsCableUpstreamChannel" {
+ value 205;
+ description
+ "CATV Upstream Channel";
+ }
+ enum "econet" {
+ value 206;
+ description
+ "Acorn Econet";
+ }
+ enum "pon155" {
+ value 207;
+ description
+ "FSAN 155Mb Symetrical PON interface";
+ }
+ enum "pon622" {
+ value 208;
+ description
+ "FSAN622Mb Symetrical PON interface";
+ }
+ enum "bridge" {
+ value 209;
+ description
+ "Transparent bridge interface";
+ }
+ enum "linegroup" {
+ value 210;
+ description
+ "Interface common to multiple lines";
+ }
+ enum "voiceEMFGD" {
+ value 211;
+ description
+ "voice E&M Feature Group D";
+ }
+ enum "voiceFGDEANA" {
+ value 212;
+ description
+ "voice FGD Exchange Access North American";
+ }
+ enum "voiceDID" {
+ value 213;
+ description
+ "voice Direct Inward Dialing";
+ }
+ enum "mpegTransport" {
+ value 214;
+ description
+ "MPEG transport interface";
+ }
+ enum "sixToFour" {
+ value 215;
+ status deprecated;
+ description
+ "6to4 interface (DEPRECATED)";
+ reference
+ "RFC 4087 - IP Tunnel MIB";
+ }
+ enum "gtp" {
+ value 216;
+ description
+ "GTP (GPRS Tunneling Protocol)";
+ }
+ enum "pdnEtherLoop1" {
+ value 217;
+ description
+ "Paradyne EtherLoop 1";
+ }
+ enum "pdnEtherLoop2" {
+ value 218;
+ description
+ "Paradyne EtherLoop 2";
+ }
+ enum "opticalChannelGroup" {
+ value 219;
+ description
+ "Optical Channel Group";
+ }
+ enum "homepna" {
+ value 220;
+ description
+ "HomePNA ITU-T G.989";
+ }
+ enum "gfp" {
+ value 221;
+ description
+ "Generic Framing Procedure (GFP)";
+ }
+ enum "ciscoISLvlan" {
+ value 222;
+ description
+ "Layer 2 Virtual LAN using Cisco ISL";
+ }
+ enum "actelisMetaLOOP" {
+ value 223;
+ description
+ "Acteleis proprietary MetaLOOP High Speed Link";
+ }
+ enum "fcipLink" {
+ value 224;
+ description
+ "FCIP Link";
+ }
+ enum "rpr" {
+ value 225;
+ description
+ "Resilient Packet Ring Interface Type";
+ }
+ enum "qam" {
+ value 226;
+ description
+ "RF Qam Interface";
+ }
+ enum "lmp" {
+ value 227;
+ description
+ "Link Management Protocol";
+ reference
+ "RFC 4327 - Link Management Protocol (LMP) Management
+ Information Base (MIB)";
+ }
+ enum "cblVectaStar" {
+ value 228;
+ description
+ "Cambridge Broadband Networks Limited VectaStar";
+ }
+ enum "docsCableMCmtsDownstream" {
+ value 229;
+ description
+ "CATV Modular CMTS Downstream Interface";
+ }
+ enum "adsl2" {
+ value 230;
+ status deprecated;
+ description
+ "Asymmetric Digital Subscriber Loop Version 2
+ (DEPRECATED/OBSOLETED - please use adsl2plus(238)
+ instead)";
+ reference
+ "RFC 4706 - Definitions of Managed Objects for Asymmetric
+ Digital Subscriber Line 2 (ADSL2)";
+ }
+ enum "macSecControlledIF" {
+ value 231;
+ description
+ "MACSecControlled";
+ }
+ enum "macSecUncontrolledIF" {
+ value 232;
+ description
+ "MACSecUncontrolled";
+ }
+ enum "aviciOpticalEther" {
+ value 233;
+ description
+ "Avici Optical Ethernet Aggregate";
+ }
+ enum "atmbond" {
+ value 234;
+ description
+ "atmbond";
+ }
+ enum "voiceFGDOS" {
+ value 235;
+ description
+ "voice FGD Operator Services";
+ }
+ enum "mocaVersion1" {
+ value 236;
+ description
+ "MultiMedia over Coax Alliance (MoCA) Interface
+ as documented in information provided privately to IANA";
+ }
+ enum "ieee80216WMAN" {
+ value 237;
+ description
+ "IEEE 802.16 WMAN interface";
+ }
+ enum "adsl2plus" {
+ value 238;
+ description
+ "Asymmetric Digital Subscriber Loop Version 2,
+ Version 2 Plus and all variants";
+ }
+ enum "dvbRcsMacLayer" {
+ value 239;
+ description
+ "DVB-RCS MAC Layer";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "dvbTdm" {
+ value 240;
+ description
+ "DVB Satellite TDM";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "dvbRcsTdma" {
+ value 241;
+ description
+ "DVB-RCS TDMA";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "x86Laps" {
+ value 242;
+ description
+ "LAPS based on ITU-T X.86/Y.1323";
+ }
+ enum "wwanPP" {
+ value 243;
+ description
+ "3GPP WWAN";
+ }
+ enum "wwanPP2" {
+ value 244;
+ description
+ "3GPP2 WWAN";
+ }
+ enum "voiceEBS" {
+ value 245;
+ description
+ "voice P-phone EBS physical interface";
+ }
+ enum "ifPwType" {
+ value 246;
+ description
+ "Pseudowire interface type";
+ reference
+ "RFC 5601 - Pseudowire (PW) Management Information Base";
+ }
+ enum "ilan" {
+ value 247;
+ description
+ "Internal LAN on a bridge per IEEE 802.1ap";
+ }
+ enum "pip" {
+ value 248;
+ description
+ "Provider Instance Port on a bridge per IEEE 802.1ah PBB";
+ }
+ enum "aluELP" {
+ value 249;
+ description
+ "Alcatel-Lucent Ethernet Link Protection";
+ }
+ enum "gpon" {
+ value 250;
+ description
+ "Gigabit-capable passive optical networks (G-PON) as per
+ ITU-T G.948";
+ }
+ enum "vdsl2" {
+ value 251;
+ description
+ "Very high speed digital subscriber line Version 2
+ (as per ITU-T Recommendation G.993.2)";
+ reference
+ "RFC 5650 - Definitions of Managed Objects for Very High
+ Speed Digital Subscriber Line 2 (VDSL2)";
+ }
+ enum "capwapDot11Profile" {
+ value 252;
+ description
+ "WLAN Profile Interface";
+ reference
+ "RFC 5834 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Binding MIB for
+ IEEE 802.11";
+ }
+ enum "capwapDot11Bss" {
+ value 253;
+ description
+ "WLAN BSS Interface";
+ reference
+ "RFC 5834 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Binding MIB for
+ IEEE 802.11";
+ }
+ enum "capwapWtpVirtualRadio" {
+ value 254;
+ description
+ "WTP Virtual Radio Interface";
+ reference
+ "RFC 5833 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Base MIB";
+ }
+ enum "bits" {
+ value 255;
+ description
+ "bitsport";
+ }
+ enum "docsCableUpstreamRfPort" {
+ value 256;
+ description
+ "DOCSIS CATV Upstream RF Port";
+ }
+ enum "cableDownstreamRfPort" {
+ value 257;
+ description
+ "CATV downstream RF port";
+ }
+ enum "vmwareVirtualNic" {
+ value 258;
+ description
+ "VMware Virtual Network Interface";
+ }
+ enum "ieee802154" {
+ value 259;
+ description
+ "IEEE 802.15.4 WPAN interface";
+ reference
+ "IEEE 802.15.4-2006";
+ }
+ enum "otnOdu" {
+ value 260;
+ description
+ "OTN Optical Data Unit";
+ }
+ enum "otnOtu" {
+ value 261;
+ description
+ "OTN Optical channel Transport Unit";
+ }
+ enum "ifVfiType" {
+ value 262;
+ description
+ "VPLS Forwarding Instance Interface Type";
+ }
+ enum "g9981" {
+ value 263;
+ description
+ "G.998.1 bonded interface";
+ }
+ enum "g9982" {
+ value 264;
+ description
+ "G.998.2 bonded interface";
+ }
+ enum "g9983" {
+ value 265;
+ description
+ "G.998.3 bonded interface";
+ }
+ enum "aluEpon" {
+ value 266;
+ description
+ "Ethernet Passive Optical Networks (E-PON)";
+ }
+ enum "aluEponOnu" {
+ value 267;
+ description
+ "EPON Optical Network Unit";
+ }
+ enum "aluEponPhysicalUni" {
+ value 268;
+ description
+ "EPON physical User to Network interface";
+ }
+ enum "aluEponLogicalLink" {
+ value 269;
+ description
+ "The emulation of a point-to-point link over the EPON
+ layer";
+ }
+ enum "aluGponOnu" {
+ value 270;
+ description
+ "GPON Optical Network Unit";
+ reference
+ "ITU-T G.984.2";
+ }
+ enum "aluGponPhysicalUni" {
+ value 271;
+ description
+ "GPON physical User to Network interface";
+ reference
+ "ITU-T G.984.2";
+ }
+ enum "vmwareNicTeam" {
+ value 272;
+ description
+ "VMware NIC Team";
+ }
+ // value 273 reserved by IANA
+ }
+ description
+ "This data type is used as the syntax of the 'type'
+ leaf in the 'interface' list in the YANG module
+ ietf-interface.
+
+ The definition of this typedef with the
+ addition of newly assigned values is published
+ periodically by the IANA, in either the Assigned
+ Numbers RFC, or some derivative of it specific to
+ Internet Network Management number assignments. (The
+ latest arrangements can be obtained by contacting the
+ IANA.)
+
+ Requests for new values should be made to IANA via
+ email (iana&iana.org).";
+ reference
+ "IANA ifType definitions registry.
+ <http://www.iana.org/assignments/smi-numbers>";
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ietf-interfaces@2013-07-04.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ietf-interfaces@2013-07-04.yang
new file mode 100644
index 0000000..9db753c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ietf-interfaces@2013-07-04.yang
@@ -0,0 +1,673 @@
+module ietf-interfaces {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+ prefix if;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import iana-if-type {
+ prefix ianaift;
+ }
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ WG Chair: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>";
+
+ description
+ "This module contains a collection of YANG definitions for
+ managing network interfaces.
+
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-07-04 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: A YANG Data Model for Interface Management";
+ }
+
+ /* Typedefs */
+
+ typedef interface-ref {
+ type leafref {
+ path "/if:interfaces/if:interface/if:name";
+ }
+ description
+ "This type is used by data models that need to reference
+ configured interfaces.";
+ }
+
+ typedef interface-state-ref {
+ type leafref {
+ path "/if:interfaces-state/if:interface/if:name";
+ }
+ description
+ "This type is used by data models that need to reference
+ the operationally present interfaces.";
+ }
+
+ /* Features */
+
+ feature arbitrary-names {
+ description
+ "This feature indicates that the device allows user-controlled
+ interfaces to be named arbitrarily.";
+ }
+
+ feature pre-provisioning {
+ description
+ "This feature indicates that the device supports
+ pre-provisioning of interface configuration, i.e., it is
+ possible to configure an interface whose physical interface
+ hardware is not present on the device.";
+ }
+
+ feature if-mib {
+ description
+ "This feature indicates that the device implements IF-MIB.";
+ reference
+ "RFC 2863: The Interfaces Group MIB";
+ }
+
+ /* Data nodes */
+
+ container interfaces {
+ description
+ "Interface configuration parameters.";
+
+ list interface {
+ key "name";
+
+ description
+ "The list of configured interfaces on the device.
+
+ The operational state of an interface is available in the
+ /interfaces-state/interface list. If the configuration of a
+ system-controlled interface cannot be used by the system
+ (e.g., the interface hardware present does not match the
+ interface type), then the configuration is not applied to
+ the system-controlled interface shown in the
+ /interfaces-state/interface list. If the the configuration
+ of a user-controlled interface cannot be used by the system,
+ the configured interface is not instantiated in the
+ /interfaces-state/interface list.";
+
+ leaf name {
+ type string;
+ description
+ "The name of the interface.
+
+ A device MAY restrict the allowed values for this leaf,
+ possibly depending on the type of the interface.
+
+ For system-controlled interfaces, this leaf is the
+ device-specific name of the interface. The 'config false'
+ list /interfaces-state/interface contains the currently
+ existing interfaces on the device.
+
+ If a client tries to create configuration for a
+ system-controlled interface that is not present in the
+ /interfaces-state/interface list, the server MAY reject
+ the request, if the implementation does not support
+ pre-provisioning of interfaces, or if the name refers to
+ an interface that can never exist in the system. A
+ NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.
+
+ If the device supports pre-provisioning of interface
+ configuration, the feature 'pre-provisioning' is
+ advertised.
+
+ If the device allows arbitrarily named user-controlled
+ interfaces, the feature 'arbitrary-names' is advertised.
+
+ When a configured user-controlled interface is created by
+ the system, it is instantiated with the same name in the
+ /interface-state/interface list. Since the name in that
+ list MAY be mapped to ifName by an implementation, such an
+ implementation MUST restrict the allowed values for this
+ leaf so that it matches the restrictions of ifName.
+
+ If a NETCONF server that implements this restriction is
+ sent a value that doesn't match the restriction, it MUST
+ reply with an rpc-error with the error-tag
+ 'invalid-value'.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "A textual description of the interface.
+
+ This leaf MAY be mapped to ifAlias by an implementation.
+ Such an implementation MUST restrict the allowed values
+ for this leaf so that it matches the restrictions of
+ ifAlias.
+
+ If a NETCONF server that implements this restriction is
+ sent a value that doesn't match the restriction, it MUST
+ reply with an rpc-error with the error-tag
+ 'invalid-value'.
+
+ Since ifAlias is defined to be stored in non-volatile
+ storage, the MIB implementation MUST map ifAlias to the
+ value of 'description' in the persistently stored
+ datastore.
+
+ Specifically, if the device supports ':startup', when
+ ifAlias is read the device MUST return the value of
+ 'description' in the 'startup' datastore, and when it is
+ written, it MUST be written to the 'running' and 'startup'
+ datastores. Note that it is up to the implementation if
+ it modifies this single leaf in 'startup', or if it
+ performs an implicit copy-config from 'running' to
+ 'startup'.
+
+ If the device does not support ':startup', ifAlias MUST
+ be mapped to the 'description' leaf in the 'running'
+ datastore.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAlias";
+ }
+
+ leaf type {
+ type ianaift:iana-if-type;
+ mandatory true;
+ description
+ "The type of the interface.
+
+ When an interface entry is created, a server MAY
+ initialize the type leaf with a valid value, e.g., if it
+ is possible to derive the type from the name of the
+ interface.
+
+ If a client tries to set the type of an interface to a
+ value that can never be used by the system, e.g., if the
+ type is not supported or if the type does not match the
+ name of the interface, the server MUST reject the request.
+ A NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf enabled {
+ type boolean;
+ default "true";
+ description
+ "This leaf contains the configured, desired state of the
+ interface.
+
+ Systems that implement the IF-MIB use the value of this
+ leaf in the 'running' datastore to set
+ IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
+ has been initialized, as described in RFC 2863.
+
+ Changes in this leaf in the 'running' datastore are
+ reflected in ifAdminStatus, but if ifAdminStatus is
+ changed over SNMP, this leaf is not affected.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf link-up-down-trap-enable {
+ if-feature if-mib;
+ type enumeration {
+ enum enabled {
+ value 1;
+ }
+ enum disabled {
+ value 2;
+ }
+ }
+ description
+ "Controls whether linkUp/linkDown SNMP notifications
+ should be generated for this interface.
+
+ If this node is not configured, the value 'enabled' is
+ operationally used by the server for interfaces which do
+ not operate on top of any other interface (i.e., there are
+ no 'lower-layer-if' entries), and 'disabled' otherwise.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifLinkUpDownTrapEnable";
+ }
+ }
+ }
+
+ container interfaces-state {
+ config false;
+ description
+ "Data nodes for the operational state of interfaces.";
+
+ list interface {
+ key "name";
+
+ description
+ "The list of interfaces on the device.
+
+ System-controlled interfaces created by the system are
+ always present in this list, whether they are configured or
+ not.";
+
+ leaf name {
+ type string;
+ description
+ "The name of the interface.
+
+ This leaf MAY be mapped to ifName by an implementation.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifName";
+ }
+
+ leaf type {
+ type ianaift:iana-if-type;
+ mandatory true;
+ description
+ "The type of the interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf admin-status {
+ if-feature if-mib;
+ type enumeration {
+ enum up {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum down {
+ value 2;
+ description
+ "Not ready to pass packets and not in some test mode.";
+ }
+ enum testing {
+ value 3;
+ description
+ "In some test mode.";
+ }
+ }
+ mandatory true;
+ description
+ "The desired state of the interface.
+
+ This leaf has the same read semantics as ifAdminStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf oper-status {
+ type enumeration {
+ enum up {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum down {
+ value 2;
+ description
+ "The interface does not pass any packets.";
+ }
+ enum testing {
+ value 3;
+ description
+ "In some test mode. No operational packets can
+ be passed.";
+ }
+ enum unknown {
+ value 4;
+ description
+ "Status cannot be determined for some reason.";
+ }
+ enum dormant {
+ value 5;
+ description
+ "Waiting for some external event.";
+ }
+ enum not-present {
+ value 6;
+ description
+ "Some component (typically hardware) is missing.";
+ }
+ enum lower-layer-down {
+ value 7;
+ description
+ "Down due to state of lower-layer interface(s).";
+ }
+ }
+ mandatory true;
+ description
+ "The current operational state of the interface.
+
+ This leaf has the same semantics as ifOperStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOperStatus";
+ }
+
+ leaf last-change {
+ type yang:date-and-time;
+ description
+ "The time the interface entered its current operational
+ state. If the current state was entered prior to the
+ last re-initialization of the local network management
+ subsystem, then this node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifLastChange";
+ }
+
+ leaf if-index {
+ if-feature if-mib;
+ type int32 {
+ range "1..2147483647";
+ }
+ mandatory true;
+ description
+ "The ifIndex value for the ifEntry represented by this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifIndex";
+ }
+
+ leaf phys-address {
+ type yang:phys-address;
+ description
+ "The interface's address at its protocol sub-layer. For
+ example, for an 802.x interface, this object normally
+ contains a MAC address. The interface's media-specific
+ modules must define the bit and byte ordering and the
+ format of the value of this object. For interfaces that do
+ not have such an address (e.g., a serial line), this node
+ is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifPhysAddress";
+ }
+
+ leaf-list higher-layer-if {
+ type interface-state-ref;
+ description
+ "A list of references to interfaces layered on top of this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifStackTable";
+ }
+
+ leaf-list lower-layer-if {
+ type interface-state-ref;
+ description
+ "A list of references to interfaces layered underneath this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifStackTable";
+ }
+
+ leaf speed {
+ type yang:gauge64;
+ units "bits / second";
+ description
+ "An estimate of the interface's current bandwidth in bits
+ per second. For interfaces that do not vary in
+ bandwidth or for those where no accurate estimation can
+ be made, this node should contain the nominal bandwidth.
+ For interfaces that have no concept of bandwidth, this
+ node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifSpeed, ifHighSpeed";
+ }
+
+ container statistics {
+ description
+ "A collection of interface-related statistics objects.";
+
+ leaf discontinuity-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time on the most recent occasion at which any one or
+ more of this interface's counters suffered a
+ discontinuity. If no such discontinuities have occurred
+ since the last re-initialization of the local management
+ subsystem, then this node contains the time the local
+ management subsystem re-initialized itself.";
+ }
+
+ leaf in-octets {
+ type yang:counter64;
+ description
+ "The total number of octets received on the interface,
+ including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInOctets";
+ }
+ leaf in-unicast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were not addressed to a
+ multicast or broadcast address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
+ }
+ leaf in-broadcast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were addressed to a broadcast
+ address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInBroadcastPkts";
+ }
+ leaf in-multicast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were addressed to a multicast
+ address at this sub-layer. For a MAC layer protocol,
+ this includes both Group and Functional addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInMulticastPkts";
+ }
+ leaf in-discards {
+ type yang:counter32;
+ description
+ "The number of inbound packets which were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being deliverable to a higher-layer
+ protocol. One possible reason for discarding such a
+ packet could be to free up buffer space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInDiscards";
+ }
+ leaf in-errors {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of inbound
+ packets that contained errors preventing them from being
+ deliverable to a higher-layer protocol. For character-
+ oriented or fixed-length interfaces, the number of
+ inbound transmission units that contained errors
+ preventing them from being deliverable to a higher-layer
+ protocol.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInErrors";
+ }
+ leaf in-unknown-protos {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of packets
+ received via the interface which were discarded because
+ of an unknown or unsupported protocol. For
+ character-oriented or fixed-length interfaces that
+ support protocol multiplexing the number of transmission
+ units received via the interface which were discarded
+ because of an unknown or unsupported protocol. For any
+ interface that does not support protocol multiplexing,
+ this counter is not present.
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
+ }
+
+ leaf out-octets {
+ type yang:counter64;
+ description
+ "The total number of octets transmitted out of the
+ interface, including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
+ }
+ leaf out-unicast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were not addressed
+ to a multicast or broadcast address at this sub-layer,
+ including those that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
+ }
+ leaf out-broadcast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were addressed to a
+ broadcast address at this sub-layer, including those
+ that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutBroadcastPkts";
+ }
+ leaf out-multicast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were addressed to a
+ multicast address at this sub-layer, including those
+ that were discarded or not sent. For a MAC layer
+ protocol, this includes both Group and Functional
+ addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutMulticastPkts";
+ }
+ leaf out-discards {
+ type yang:counter32;
+ description
+ "The number of outbound packets which were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being transmitted. One possible reason
+ for discarding such a packet could be to free up buffer
+ space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutDiscards";
+ }
+ leaf out-errors {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of outbound
+ packets that could not be transmitted because of errors.
+ For character-oriented or fixed-length interfaces, the
+ number of outbound transmission units that could not be
+ transmitted because of errors.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutErrors";
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ietf-yang-types@2013-05-16.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ietf-yang-types@2013-05-16.yang
new file mode 100644
index 0000000..6c82d9d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/ietf-yang-types@2013-05-16.yang
@@ -0,0 +1,471 @@
+module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ WG Chair: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2013-05-16 {
+ description
+ "This revision adds the following new data types:
+ - yang-identifier
+ - hex-string
+ - uuid
+ - dotted-quad";
+ reference
+ "RFC XXXX: Common YANG Data Types";
+ }
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2
+ (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2
+ (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2
+ (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2
+ (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined in RFC 6020, page 163.
+ An identifier must start with an alphabetic character or
+ an underscore followed by an arbitrary sequence of
+ alphabetic or numeric characters, underscores, hyphens
+ or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lower-case or upper-case character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using
+ the time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually
+ referring to the notion of local time) uses the time-offset
+ -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2
+ (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence
+ happened. The specific occurrence must be defined in the
+ description of any schema node defined using this type. When
+ the specific occurrence occurred prior to the last time the
+ associated timeticks attribute was zero, then the timestamp
+ value is zero. Note that this requires all timestamp values
+ to be reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ /*** collection of string types ***/
+
+ typedef hex-string {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "A hexadecimal string with octets represented as hex digits
+ separated by colons. The canonical representation uses
+ lowercase characters.";
+ }
+
+ typedef uuid {
+ type string {
+ pattern '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-'
+ + '[0-9a-fA-F]{4}-[0-9a-fA-F]{12}';
+ }
+ description
+ "A Universally Unique IDentifier in the string representation
+ defined in RFC 4122. The canonical representation uses
+ lowercase characters.
+
+ The following is an example of a UUID in string representation:
+ f81d4fae-7dec-11d0-a765-00a0c91e6bf6
+ ";
+ reference
+ "RFC 4122: A Universally Unique IDentifier (UUID) URN
+ Namespace";
+ }
+
+ typedef dotted-quad {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])';
+ }
+ description
+ "An unsigned 32-bit number expressed in the dotted-quad
+ notation, i.e., four octets written as decimal numbers
+ and separated with the '.' (full stop) character.";
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/sal-remote@2014-01-14.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/sal-remote@2014-01-14.yang
new file mode 100644
index 0000000..d12e252
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/sal-remote@2014-01-14.yang
@@ -0,0 +1,98 @@
+module sal-remote {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
+ prefix "sal-remote";
+
+
+ organization "Cisco Systems, Inc.";
+ contact "Martin Bobak <mbobak@cisco.com>";
+
+ description
+ "This module contains the definition of methods related to
+ sal remote model.
+
+ Copyright (c)2013 Cisco Systems, Inc. All rights reserved.
+
+ This program and the accompanying materials are made available
+ under the terms of the Eclipse Public License v1.0 which
+ accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html";
+
+ revision "2014-01-14" {
+ description
+ "Initial revision";
+ }
+
+
+ typedef q-name {
+ type string;
+ reference
+ "http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#QName";
+ }
+
+ rpc create-data-change-event-subscription {
+ input {
+ leaf path {
+ type instance-identifier;
+ description "Subtree path. ";
+ }
+ }
+ output {
+ leaf stream-name {
+ type string;
+ description "Notification stream name.";
+ }
+ }
+ }
+
+ notification data-changed-notification {
+ description "Data change notification.";
+ list data-change-event {
+ key path;
+ leaf path {
+ type instance-identifier;
+ }
+ leaf store {
+ type enumeration {
+ enum config;
+ enum operation;
+ }
+ }
+ leaf operation {
+ type enumeration {
+ enum created;
+ enum updated;
+ enum deleted;
+ }
+ }
+ anyxml data{
+ description "DataObject ";
+ }
+ }
+ }
+
+ rpc create-notification-stream {
+ input {
+ leaf-list notifications {
+ type q-name;
+ description "Notification QNames";
+ }
+ }
+ output {
+ leaf notification-stream-identifier {
+ type string;
+ description "Unique notification stream identifier, in which notifications will be propagated";
+ }
+ }
+ }
+
+ rpc begin-transaction{
+ output{
+ anyxml data-modification-transaction{
+ description "DataModificationTransaction xml";
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/simple-nodes.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/simple-nodes.yang
new file mode 100644
index 0000000..6c16254
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/simple-nodes.yang
@@ -0,0 +1,80 @@
+module simple-nodes {
+ yang-version 1;
+ namespace "urn:opendaylight:simple-nodes";
+ prefix "sn";
+
+ description
+ "test file containing yang data nodes";
+
+ revision "2013-07-30" {
+ description
+ "Initial revision.";
+ reference "will be defined";
+ }
+
+ container users {
+ leaf user {
+ type string;
+ }
+
+ leaf group {
+ type string;
+ }
+ }
+
+ list user {
+ key "name class";
+ leaf name {
+ type string;
+ }
+ leaf full-name {
+ type string;
+ }
+ leaf class {
+ type string;
+ }
+ }
+
+ list userWithoutClass {
+ key "name";
+ leaf name {
+ type string;
+ }
+ leaf full-name {
+ type string;
+ }
+ container inner-container {
+ leaf inner-list {
+ type uint16;
+ }
+ }
+ }
+
+ container food {
+ choice snack {
+ case sports-arena {
+ leaf pretzel {
+ type string;
+ }
+ leaf beer {
+ type string;
+ }
+ container nonalcoholic {
+ leaf beer {
+ type string;
+ }
+ }
+ }
+ case late-night {
+ leaf chocolate {
+ type enumeration {
+ enum dark;
+ enum milk;
+ enum first-available;
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/subscribe-to-notification.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/subscribe-to-notification.yang
new file mode 100644
index 0000000..5fe7df7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/subscribe-to-notification.yang
@@ -0,0 +1,18 @@
+module subscribe-to-notification {
+
+ yang-version 1;
+ namespace "subscribe:to:notification";
+ prefix "subs-to-notifi";
+
+ description
+ "Added input parameters to rpc create-data-change-event-subscription and to create-notification-stream";
+
+ revision "2016-10-28" {
+ }
+
+ container "notifi"{
+ leaf "location"{
+ type string;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/toaster.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/toaster.yang
new file mode 100644
index 0000000..571ed0c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/full-versions/yangs/toaster.yang
@@ -0,0 +1,197 @@
+ module toaster {
+
+ yang-version 1;
+
+ namespace
+ "http://netconfcentral.org/ns/toaster";
+
+ prefix toast;
+
+ organization "Netconf Central";
+
+ contact
+ "Andy Bierman <andy@netconfcentral.org>";
+
+ description
+ "YANG version of the TOASTER-MIB.";
+
+ revision "2009-11-20" {
+ description
+ "Toaster module in progress.";
+ }
+
+
+ identity toast-type {
+ description
+ "Base for all bread types supported by the toaster.
+ New bread types not listed here nay be added in the
+ future.";
+ }
+
+ identity white-bread {
+ base toast:toast-type;
+ description "White bread.";
+ }
+
+ identity wheat-bread {
+ base toast-type;
+ description "Wheat bread.";
+ }
+
+ identity wonder-bread {
+ base toast-type;
+ description "Wonder bread.";
+ }
+
+ identity frozen-waffle {
+ base toast-type;
+ description "Frozen waffle.";
+ }
+
+ identity frozen-bagel {
+ base toast-type;
+ description "Frozen bagel.";
+ }
+
+ identity hash-brown {
+ base toast-type;
+ description "Hash browned potatos.";
+ }
+
+ typedef DisplayString {
+ type string {
+ length "0 .. 255";
+ }
+ description
+ "YANG version of the SMIv2 DisplayString TEXTUAL-CONVENTION.";
+ reference
+ "RFC 2579, section 2.";
+
+ }
+
+ container toaster {
+ presence
+ "Indicates the toaster service is available";
+ description
+ "Top-level container for all toaster database objects.";
+ leaf toasterManufacturer {
+ type DisplayString;
+ config false;
+ mandatory true;
+ description
+ "The name of the toaster's manufacturer. For instance,
+ Microsoft Toaster.";
+ }
+
+ leaf toasterModelNumber {
+ type DisplayString;
+ config false;
+ mandatory true;
+ description
+ "The name of the toaster's model. For instance,
+ Radiant Automatic.";
+ }
+
+ leaf toasterStatus {
+ type enumeration {
+ enum "up" {
+ value 1;
+ description
+ "The toaster knob position is up.
+ No toast is being made now.";
+ }
+ enum "down" {
+ value 2;
+ description
+ "The toaster knob position is down.
+ Toast is being made now.";
+ }
+ }
+ config false;
+ mandatory true;
+ description
+ "This variable indicates the current state of
+ the toaster.";
+ }
+ } // container toaster
+
+ rpc make-toast {
+ description
+ "Make some toast.
+ The toastDone notification will be sent when
+ the toast is finished.
+ An 'in-use' error will be returned if toast
+ is already being made.
+ A 'resource-denied' error will be returned
+ if the toaster service is disabled.";
+ input {
+ leaf toasterDoneness {
+ type uint32 {
+ range "1 .. 10";
+ }
+ default '5';
+ description
+ "This variable controls how well-done is the
+ ensuing toast. It should be on a scale of 1 to 10.
+ Toast made at 10 generally is considered unfit
+ for human consumption; toast made at 1 is warmed
+ lightly.";
+ }
+
+ leaf toasterToastType {
+ type identityref {
+ base toast:toast-type;
+ }
+ default 'wheat-bread';
+ description
+ "This variable informs the toaster of the type of
+ material that is being toasted. The toaster
+ uses this information, combined with
+ toasterDoneness, to compute for how
+ long the material must be toasted to achieve
+ the required doneness.";
+ }
+ }
+ } // rpc make-toast
+
+ rpc testOutput {
+ output {
+ leaf textOut {
+ type string;
+ }
+ }
+ }
+
+ rpc cancel-toast {
+ description
+ "Stop making toast, if any is being made.
+ A 'resource-denied' error will be returned
+ if the toaster service is disabled.";
+ } // rpc cancel-toast
+
+ notification toastDone {
+ description
+ "Indicates that the toast in progress has completed.";
+ leaf toastStatus {
+ type enumeration {
+ enum "done" {
+ value 0;
+ description "The toast is done.";
+ }
+ enum "cancelled" {
+ value 1;
+ description
+ "The toast was cancelled.";
+ }
+ enum "error" {
+ value 2;
+ description
+ "The toaster service was disabled or
+ the toaster is broken.";
+ }
+ }
+ description
+ "Indicates the final toast status";
+ }
+ } // notification toastDone
+ } // module toaster
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/iid-value.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/iid-value.yang
new file mode 100644
index 0000000..4e536df
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/iid-value.yang
@@ -0,0 +1,23 @@
+module iid-value-module {
+ namespace "iid:value:module";
+
+ prefix "iidvm";
+ revision 2016-09-12 {
+ }
+
+ container cont-iid {
+ list iid-list{
+ key "iid-leaf";
+ leaf iid-leaf{
+ type instance-identifier;
+ }
+ }
+
+ list values-iid{
+ key "value-iid";
+ leaf value-iid{
+ type string;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHMergeOperationOnContainer.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHMergeOperationOnContainer.json
new file mode 100644
index 0000000..1483920
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHMergeOperationOnContainer.json
@@ -0,0 +1,43 @@
+{
+ "ietf-yang-patch:yang-patch" : {
+ "patch-id" : "Test merge operation",
+ "comment" : "This is test patch for merge operation on container",
+ "edit" : [
+ {
+ "edit-id": "edit1",
+ "operation": "create",
+ "target": "/",
+ "value": {
+ "patch-cont": {
+ "my-list1": [
+ {
+ "name": "my-list1 - A",
+ "my-leaf11": "I am leaf11-0",
+ "my-leaf12": "I am leaf12-1"
+ },
+ {
+ "name": "my-list1 - B",
+ "my-leaf11": "I am leaf11-0",
+ "my-leaf12": "I am leaf12-1"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "edit-id": "edit2",
+ "operation": "merge",
+ "target": "/",
+ "value": {
+ "patch-cont": {
+ "my-list1": {
+ "name": "my-list1 - Merged",
+ "my-leaf11": "I am leaf11-0",
+ "my-leaf12": "I am leaf12-1"
+ }
+ }
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHMergeOperationOnList.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHMergeOperationOnList.json
new file mode 100644
index 0000000..3b809e0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHMergeOperationOnList.json
@@ -0,0 +1,32 @@
+{
+ "ietf-yang-patch:yang-patch" : {
+ "patch-id" : "Test merge operation",
+ "comment" : "This is test patch for merge operation on list",
+ "edit" : [
+ {
+ "edit-id": "edit1",
+ "operation": "replace",
+ "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']",
+ "value": {
+ "my-list2": {
+ "name": "my-leaf20",
+ "my-leaf21": "I am leaf21-0",
+ "my-leaf22": "I am leaf22-0"
+ }
+ }
+ },
+ {
+ "edit-id": "edit2",
+ "operation": "merge",
+ "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf21']",
+ "value": {
+ "my-list2": {
+ "name": "my-leaf21",
+ "my-leaf21": "I am leaf21-1",
+ "my-leaf22": "I am leaf22-1"
+ }
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHSimpleLeafValue.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHSimpleLeafValue.json
new file mode 100644
index 0000000..4a109ef
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHSimpleLeafValue.json
@@ -0,0 +1,17 @@
+{
+ "ietf-yang-patch:yang-patch" : {
+
+ "patch-id" : "test-patch",
+ "comment" : "this is test patch for simple leaf value",
+ "edit" : [
+ {
+ "edit-id": "edit1",
+ "operation": "replace",
+ "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']/instance-identifier-patch-module:name",
+ "value": {
+ "name": "my-leaf20"
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdata.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdata.json
new file mode 100644
index 0000000..e027a76
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdata.json
@@ -0,0 +1,35 @@
+{
+ "ietf-yang-patch:yang-patch" : {
+
+ "patch-id" : "test-patch",
+ "comment" : "this is test patch",
+ "edit" : [
+ {
+ "edit-id": "edit1",
+ "operation": "replace",
+ "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']",
+ "value": {
+ "my-list2": {
+ "name": "my-leaf20",
+ "my-leaf21": "I am leaf21-0",
+ "my-leaf22": "I am leaf22-0"
+ }
+ }
+ },
+
+ {
+ "edit-id": "edit2",
+ "operation": "replace",
+ "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']",
+ "value": {
+ "my-list2": {
+ "name": "my-leaf20",
+ "my-leaf21": "I am leaf21-1",
+ "my-leaf22": "I am leaf22-1",
+ "my-leaf-list": ["listelement"]
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataCompleteTargetInURI.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataCompleteTargetInURI.json
new file mode 100644
index 0000000..1b170c7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataCompleteTargetInURI.json
@@ -0,0 +1,44 @@
+{
+ "ietf-yang-patch:yang-patch" : {
+
+ "patch-id" : "test-patch",
+ "comment" : "Test to create and replace data in container directly using / sign as a target",
+ "edit" : [
+ {
+ "edit-id": "edit1",
+ "operation": "create",
+ "target": "/",
+ "value": {
+ "patch-cont": {
+ "my-list1": [
+ {
+ "name": "my-list1 - A",
+ "my-leaf11": "I am leaf11-0",
+ "my-leaf12": "I am leaf12-1"
+ },
+ {
+ "name": "my-list1 - B",
+ "my-leaf11": "I am leaf11-0",
+ "my-leaf12": "I am leaf12-1"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "edit-id": "edit2",
+ "operation": "replace",
+ "target": "/",
+ "value": {
+ "patch-cont": {
+ "my-list1": {
+ "name": "my-list1 - Replacing",
+ "my-leaf11": "I am leaf11-0",
+ "my-leaf12": "I am leaf12-1"
+ }
+ }
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json
new file mode 100644
index 0000000..4455038
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json
@@ -0,0 +1,31 @@
+{
+ "ietf-yang-patch:yang-patch" : {
+ "patch-id" : "test-patch",
+ "comment" : "this is test patch",
+ "edit" : [
+ {
+ "edit-id": "edit1",
+ "value": {
+ "my-list2": [
+ {
+ "name": "my-leaf20",
+ "my-leaf21": "I am leaf20"
+ },
+ {
+ "name": "my-leaf21",
+ "my-leaf21": "I am leaf21-1",
+ "my-leaf22": "I am leaf21-2"
+ }
+ ]
+ },
+ "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']",
+ "operation": "create"
+ },
+ {
+ "edit-id": "edit2",
+ "operation": "delete",
+ "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataValueMissing.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataValueMissing.json
new file mode 100644
index 0000000..eaf1b37
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataValueMissing.json
@@ -0,0 +1,13 @@
+{
+ "ietf-yang-patch:yang-patch" : {
+ "patch-id" : "test-patch",
+ "comment" : "this is test patch",
+ "edit" : [
+ {
+ "edit-id": "edit1",
+ "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']",
+ "operation": "create"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataValueNotSupported.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataValueNotSupported.json
new file mode 100644
index 0000000..1ad52fb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsonPATCHdataValueNotSupported.json
@@ -0,0 +1,20 @@
+{
+ "ietf-yang-patch:yang-patch" : {
+ "patch-id" : "test-patch",
+ "comment" : "this is test patch",
+ "edit" : [
+ {
+ "edit-id": "edit2",
+ "operation": "delete",
+ "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']",
+ "value": {
+ "my-list2": [
+ {
+ "name": "my-leaf20"
+ }
+ ]
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_augment_choice_container.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_augment_choice_container.json
new file mode 100644
index 0000000..e64e00e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_augment_choice_container.json
@@ -0,0 +1,5 @@
+{
+ "augment-module:case-choice-case-container1": {
+ "augment-module:case-choice-case-leaf1": "stryng"
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_augment_container.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_augment_container.json
new file mode 100644
index 0000000..e2532f2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_augment_container.json
@@ -0,0 +1,5 @@
+{
+ "augment-module:cont-augment": {
+ "augment-module:leaf1": "stryng"
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_sub_container.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_sub_container.json
new file mode 100644
index 0000000..22a1d15
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/json_sub_container.json
@@ -0,0 +1,5 @@
+{
+ "instance-identifier-module:cont1": {
+ "augment-module-leaf-list:lf11" : "/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11[.=\"lflst11_1\"]"
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsondata.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsondata.json
new file mode 100644
index 0000000..f616a8a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsondata.json
@@ -0,0 +1,14 @@
+{
+ "instance-identifier-module:cont": {
+ "cont1": {
+ "augment-module:lst11": [
+ {
+ "keyvalue111":"value1",
+ "keyvalue112":"value2",
+ "augment-augment-module:lf111":"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111=\"value1\"][augment-module:keyvalue112=\"value2\"]/augment-augment-module:lf112",
+ "augment-augment-module:lf112":"lf112 value"
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsondata_leaf_list.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsondata_leaf_list.json
new file mode 100644
index 0000000..63be4b9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/json/jsondata_leaf_list.json
@@ -0,0 +1,7 @@
+{
+ "instance-identifier-module:cont": {
+ "cont1": {
+ "augment-module-leaf-list:lf11" : "/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11[.=\"lflst11_1\"]"
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/bug7933.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/bug7933.xml
new file mode 100644
index 0000000..aa0d79e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/bug7933.xml
@@ -0,0 +1,9 @@
+<!--
+ ~ Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+
+<cont1 xmlns="instance:identifier:module"/>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlDataFindBarContainer.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlDataFindBarContainer.xml
new file mode 100644
index 0000000..6523345
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlDataFindBarContainer.xml
@@ -0,0 +1,10 @@
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+
+<foo-bar-container xmlns="bar:module">
+</foo-bar-container> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlDataFindFooContainer.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlDataFindFooContainer.xml
new file mode 100644
index 0000000..93aeff8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlDataFindFooContainer.xml
@@ -0,0 +1,10 @@
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+
+<foo-bar-container xmlns="foo:module">
+</foo-bar-container> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdata.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdata.xml
new file mode 100644
index 0000000..d7d3a6b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdata.xml
@@ -0,0 +1,28 @@
+<yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>test-patch</patch-id>
+ <comment>this is test patch</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>create</operation>
+ <target>/my-list2</target>
+ <value>
+ <my-list2 xmlns="instance:identifier:patch:module">
+ <name>my-leaf20</name>
+ <my-leaf21>I am leaf21-0</my-leaf21>
+ <my-leaf22>I am leaf22-0</my-leaf22>
+ </my-list2>
+ </value>
+ </edit>
+ <edit>
+ <edit-id>edit2</edit-id>
+ <operation>create</operation>
+ <target>/my-list2</target>
+ <value>
+ <my-list2 xmlns="instance:identifier:patch:module">
+ <name>my-leaf21</name>
+ <my-leaf21>I am leaf21-1</my-leaf21>
+ <my-leaf22>I am leaf22-1</my-leaf22>
+ </my-list2>
+ </value>
+ </edit>
+</yang-patch> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml
new file mode 100644
index 0000000..6e84c47
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml
@@ -0,0 +1,35 @@
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>test-patch</patch-id>
+ <comment>Test patch with absolute target path</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>create</operation>
+ <target>/instance-identifier-patch-module:patch-cont/my-list1/leaf1/my-list2</target>
+ <value>
+ <my-list2 xmlns="instance:identifier:patch:module">
+ <name>my-leaf20</name>
+ <my-leaf21>I am leaf21-0</my-leaf21>
+ <my-leaf22>I am leaf22-0</my-leaf22>
+ </my-list2>
+ </value>
+ </edit>
+ <edit>
+ <edit-id>edit2</edit-id>
+ <operation>create</operation>
+ <target>/instance-identifier-patch-module:patch-cont/my-list1/leaf1/my-list2</target>
+ <value>
+ <my-list2 xmlns="instance:identifier:patch:module">
+ <name>my-leaf21</name>
+ <my-leaf21>I am leaf21-1</my-leaf21>
+ <my-leaf22>I am leaf22-1</my-leaf22>
+ </my-list2>
+ </value>
+ </edit>
+</yang-patch> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml
new file mode 100644
index 0000000..23d2ce0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>test-patch</patch-id>
+ <comment>Test to create and replace data in container directly using / sign as a target</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>create</operation>
+ <target>/</target>
+ <value>
+ <patch-cont xmlns="instance:identifier:patch:module">
+ <my-list1>
+ <name>my-list1 - A</name>
+ <my-leaf11>I am leaf11-0</my-leaf11>
+ <my-leaf12>I am leaf12-1</my-leaf12>
+ </my-list1>
+ <my-list1>
+ <name>my-list1 - B</name>
+ <my-leaf11>I am leaf11-0</my-leaf11>
+ <my-leaf12>I am leaf12-1</my-leaf12>
+ </my-list1>
+ </patch-cont>
+ </value>
+ </edit>
+ <edit>
+ <edit-id>edit2</edit-id>
+ <operation>replace</operation>
+ <target>/</target>
+ <value>
+ <patch-cont xmlns="instance:identifier:patch:module">
+ <my-list1>
+ <name>my-list1 - Replacing</name>
+ <my-leaf11>I am leaf11-0</my-leaf11>
+ <my-leaf12>I am leaf12-1</my-leaf12>
+ </my-list1>
+ </patch-cont>
+ </value>
+ </edit>
+</yang-patch> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml
new file mode 100644
index 0000000..afa35bd
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>Test merge operation</patch-id>
+ <comment>This is test patch for merge operation on container</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>create</operation>
+ <target>/</target>
+ <value>
+ <patch-cont xmlns="instance:identifier:patch:module">
+ <my-list1>
+ <name>my-list1 - A</name>
+ <my-leaf11>I am leaf11-0</my-leaf11>
+ <my-leaf12>I am leaf12-1</my-leaf12>
+ </my-list1>
+ <my-list1>
+ <name>my-list1 - B</name>
+ <my-leaf11>I am leaf11-0</my-leaf11>
+ <my-leaf12>I am leaf12-1</my-leaf12>
+ </my-list1>
+ </patch-cont>
+ </value>
+ </edit>
+ <edit>
+ <edit-id>edit2</edit-id>
+ <operation>merge</operation>
+ <target>/</target>
+ <value>
+ <patch-cont xmlns="instance:identifier:patch:module">
+ <my-list1>
+ <name>my-list1 - Merged</name>
+ <my-leaf11>I am leaf11-0</my-leaf11>
+ <my-leaf12>I am leaf12-1</my-leaf12>
+ </my-list1>
+ </patch-cont>
+ </value>
+ </edit>
+</yang-patch> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml
new file mode 100644
index 0000000..ad13041
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml
@@ -0,0 +1,35 @@
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>Test merge operation</patch-id>
+ <comment>This is test patch for merge operation on list</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>replace</operation>
+ <target>/my-list2</target>
+ <value>
+ <my-list2 xmlns="instance:identifier:patch:module">
+ <name>my-leaf20</name>
+ <my-leaf21>I am leaf21-0</my-leaf21>
+ <my-leaf22>I am leaf22-0</my-leaf22>
+ </my-list2>
+ </value>
+ </edit>
+ <edit>
+ <edit-id>edit2</edit-id>
+ <operation>merge</operation>
+ <target>/my-list2</target>
+ <value>
+ <my-list2 xmlns="instance:identifier:patch:module">
+ <name>my-leaf21</name>
+ <my-leaf21>I am leaf21-1</my-leaf21>
+ <my-leaf22>I am leaf22-1</my-leaf22>
+ </my-list2>
+ </value>
+ </edit>
+</yang-patch> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataValueMissing.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataValueMissing.xml
new file mode 100644
index 0000000..eeec5ad
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataValueMissing.xml
@@ -0,0 +1,16 @@
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>test-patch</patch-id>
+ <comment>Test patch with missing value node for create operation</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>create</operation>
+ <target>/my-list2</target>
+ </edit>
+</yang-patch> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml
new file mode 100644
index 0000000..8817094
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ ~
+ ~ This program and the accompanying materials are made available under the
+ ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+<yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
+ <patch-id>test-patch</patch-id>
+ <comment>Test patch with not allowed value node for delete operation</comment>
+ <edit>
+ <edit-id>edit1</edit-id>
+ <operation>delete</operation>
+ <target>/my-list2/my-leaf21</target>
+ <value>
+ <my-list2 xmlns="instance:identifier:patch:module">
+ <name>my-leaf20</name>
+ <my-leaf21>I am leaf21-0</my-leaf21>
+ <my-leaf22>I am leaf22-0</my-leaf22>
+ </my-list2>
+ </value>
+ </edit>
+</yang-patch> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_augment_choice_container.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_augment_choice_container.xml
new file mode 100644
index 0000000..d73b300
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_augment_choice_container.xml
@@ -0,0 +1,3 @@
+<case-choice-case-container1 xmlns="augment:module">
+ <case-choice-case-leaf1>stryng</case-choice-case-leaf1>
+</case-choice-case-container1> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_augment_container.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_augment_container.xml
new file mode 100644
index 0000000..6b35e9e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_augment_container.xml
@@ -0,0 +1,3 @@
+<cont-augment xmlns="augment:module">
+ <leaf1>stryng</leaf1>
+</cont-augment> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_sub_container.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_sub_container.xml
new file mode 100644
index 0000000..f76e08d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xml_sub_container.xml
@@ -0,0 +1,6 @@
+<cont1 xmlns="instance:identifier:module">
+ <lflst11 xmlns="augment:module:leaf:list">lflst11_1</lflst11>
+ <lflst11 xmlns="augment:module:leaf:list">lflst11_2</lflst11>
+ <lflst11 xmlns="augment:module:leaf:list">lflst11_3</lflst11>
+ <lf11 xmlns:a="instance:identifier:module" xmlns:b="augment:module:leaf:list" xmlns="augment:module:leaf:list">/a:cont/a:cont1/b:lflst11[.="lflst11_1"]</lf11>
+</cont1> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmldata.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmldata.xml
new file mode 100644
index 0000000..bd558fb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmldata.xml
@@ -0,0 +1,10 @@
+<cont xmlns="instance:identifier:module">
+ <cont1>
+ <lst11 xmlns="augment:module" xmlns:c="augment:augment:module">
+ <keyvalue111>value1</keyvalue111>
+ <keyvalue112>value2</keyvalue112>
+ <lf111 xmlns="augment:augment:module" xmlns:a="instance:identifier:module" xmlns:b="augment:module" >/a:cont/a:cont1/b:lst11[b:keyvalue111="value1"][b:keyvalue112="value2"]/c:lf112</lf111>
+ <lf112 xmlns="augment:augment:module">lf112 value</lf112>
+ </lst11>
+ </cont1>
+</cont>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmldata_leaf_list.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmldata_leaf_list.xml
new file mode 100644
index 0000000..00d58c2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/xml/xmldata_leaf_list.xml
@@ -0,0 +1,8 @@
+<cont xmlns="instance:identifier:module">
+ <cont1>
+ <lflst11 xmlns="augment:module:leaf:list">lflst11_1</lflst11>
+ <lflst11 xmlns="augment:module:leaf:list">lflst11_2</lflst11>
+ <lflst11 xmlns="augment:module:leaf:list">lflst11_3</lflst11>
+ <lf11 xmlns:a="instance:identifier:module" xmlns:b="augment:module:leaf:list" xmlns="augment:module:leaf:list">/a:cont/a:cont1/b:lflst11[.="lflst11_1"]</lf11>
+ </cont1>
+</cont>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-augment-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-augment-module.yang
new file mode 100644
index 0000000..546111c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-augment-module.yang
@@ -0,0 +1,21 @@
+module augment-augment-module {
+ namespace "augment:augment:module";
+
+ prefix "aamodule";
+
+ import augment-module {prefix amodule; revision-date 2014-01-17;}
+ import instance-identifier-module {prefix imodule; revision-date 2014-01-17;}
+
+ revision 2014-01-17 {
+ }
+
+ augment "/imodule:cont/imodule:cont1/amodule:lst11" {
+ leaf lf111 {
+ type instance-identifier;
+ }
+ leaf lf112 {
+ type string;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-module-leaf-list.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-module-leaf-list.yang
new file mode 100644
index 0000000..54c305b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-module-leaf-list.yang
@@ -0,0 +1,20 @@
+module augment-module-leaf-list {
+ namespace "augment:module:leaf:list";
+
+ prefix "amodulelflst";
+
+ import instance-identifier-module {prefix imodule; revision-date 2014-01-17;}
+
+ revision 2014-01-27 {
+ }
+
+ augment "/imodule:cont/imodule:cont1" {
+ leaf-list lflst11 {
+ type string;
+ }
+ leaf lf11 {
+ type instance-identifier;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-module.yang
new file mode 100644
index 0000000..c918ef9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/augment-module.yang
@@ -0,0 +1,63 @@
+module augment-module {
+ namespace "augment:module";
+
+ prefix "amodule";
+
+ import instance-identifier-module {prefix imodule; revision-date 2014-01-17;}
+
+ revision 2014-01-17 {
+ }
+
+ augment "/imodule:cont/imodule:cont1" {
+ list lst11 {
+ key "keyvalue111 keyvalue112";
+ leaf keyvalue111 {
+ type string;
+ }
+ leaf keyvalue112 {
+ type string;
+ }
+ }
+ }
+
+ augment "/imodule:cont" {
+ container cont-augment {
+ leaf leaf1 {
+ type string;
+ }
+ }
+ }
+
+ augment "/imodule:cont" {
+ choice augment-choice1 {
+ case case1 {
+ container case-container1 {
+ leaf case-leaf1 {
+ type string;
+ }
+ }
+ }
+
+ case case2 {
+ container case-container2 {
+ leaf case-leaf2 {
+ type string;
+ }
+ }
+ }
+ }
+ }
+
+ augment "/imodule:cont/augment-choice1/case1" {
+ choice augment-choice2 {
+ case case11 {
+ container case-choice-case-container1 {
+ leaf case-choice-case-leaf1 {
+ type string;
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/bar-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/bar-module.yang
new file mode 100644
index 0000000..90de085
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/bar-module.yang
@@ -0,0 +1,11 @@
+module bar-module {
+ namespace "bar:module";
+
+ prefix "bar-module";
+ revision 2016-09-29 {
+ }
+
+ /* This container has the same name as container in foo-module */
+ container foo-bar-container {
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/foo-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/foo-module.yang
new file mode 100644
index 0000000..16b8e7f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/foo-module.yang
@@ -0,0 +1,11 @@
+module foo-module {
+ namespace "foo:module";
+
+ prefix "foo-module";
+ revision 2016-09-29 {
+ }
+
+ /* This container has the same name as container in bar-module */
+ container foo-bar-container {
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/instance-identifier-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/instance-identifier-module.yang
new file mode 100644
index 0000000..7a95a5f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/instance-identifier-module.yang
@@ -0,0 +1,13 @@
+module instance-identifier-module {
+ namespace "instance:identifier:module";
+
+ prefix "iimodule";
+ revision 2014-01-17 {
+ }
+
+ container cont {
+ container cont1 {
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/instance-identifier-patch-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/instance-identifier-patch-module.yang
new file mode 100644
index 0000000..02c1c2e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/instanceidentifier/yang/instance-identifier-patch-module.yang
@@ -0,0 +1,47 @@
+module instance-identifier-patch-module {
+ namespace "instance:identifier:patch:module";
+
+ prefix "iipmodule";
+ revision 2015-11-21 {
+ }
+
+ container patch-cont {
+ list my-list1 {
+
+ description "PATCH /restconf/config/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+
+ key name;
+
+ leaf name {
+ type string;
+ }
+
+ leaf my-leaf11 {
+ type string;
+ }
+
+ leaf my-leaf12 {
+ type string;
+ }
+
+ list my-list2 {
+ key name;
+
+ leaf name {
+ type string;
+ }
+
+ leaf my-leaf21 {
+ type string;
+ }
+
+ leaf my-leaf22 {
+ type string;
+ }
+ leaf-list my-leaf-list {
+ type string;
+ }
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-inet-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-inet-types.yang
new file mode 100644
index 0000000..de20feb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-inet-types.yang
@@ -0,0 +1,418 @@
+ module ietf-inet-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+ prefix "inet";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ typedef ip-version {
+ type enumeration {
+ enum unknown {
+ value "0";
+ description
+ "An unknown or unspecified version of the Internet protocol.";
+ }
+ enum ipv4 {
+ value "1";
+ description
+ "The IPv4 protocol as defined in RFC 791.";
+ }
+ enum ipv6 {
+ value "2";
+ description
+ "The IPv6 protocol as defined in RFC 2460.";
+ }
+ }
+ description
+ "This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.";
+ reference
+ "RFC 791: Internet Protocol
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ typedef dscp {
+ type uint8 {
+ range "0..63";
+ }
+ description
+ "The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.";
+ reference
+ "RFC 3289: Management Information Base for the Differentiated
+ Services Architecture
+ RFC 2474: Definition of the Differentiated Services Field
+ (DS Field) in the IPv4 and IPv6 Headers
+ RFC 2780: IANA Allocation Guidelines For Values In
+ the Internet Protocol and Related Headers";
+ }
+
+ typedef ipv6-flow-label {
+ type uint32 {
+ range "0..1048575";
+ }
+ description
+ "The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.";
+ reference
+ "RFC 3595: Textual Conventions for IPv6 Flow Label
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+ }
+
+ typedef port-number {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.";
+ reference
+ "RFC 768: User Datagram Protocol
+ RFC 793: Transmission Control Protocol
+ RFC 4960: Stream Control Transmission Protocol
+ RFC 4340: Datagram Congestion Control Protocol (DCCP)
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of autonomous system related types ***/
+
+ typedef as-number {
+ type uint32;
+ description
+ "The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.";
+ reference
+ "RFC 1930: Guidelines for creation, selection, and registration
+ of an Autonomous System (AS)
+ RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+ RFC 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ typedef ip-address {
+ type union {
+ type inet:ipv4-address;
+ type inet:ipv6-address;
+ }
+ description
+ "The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '(%[\p{N}\p{L}]+)?';
+ }
+ description
+ "The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format";
+ }
+
+ typedef ipv6-address {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(%[\p{N}\p{L}]+)?';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(%.+)?';
+ }
+ description
+ "The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture
+ RFC 4007: IPv6 Scoped Address Architecture
+ RFC 5952: A Recommendation for IPv6 Address Text Representation";
+ }
+
+ typedef ip-prefix {
+ type union {
+ type inet:ipv4-prefix;
+ type inet:ipv6-prefix;
+ }
+ description
+ "The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-prefix {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+ }
+ description
+ "The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.";
+ }
+
+ typedef ipv6-prefix {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(/.+)';
+ }
+ description
+ "The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** collection of domain name and URI types ***/
+
+ typedef domain-name {
+ type string {
+ pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ + '|\.';
+ length "1..253";
+ }
+ description
+ "The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492";
+ reference
+ "RFC 952: DoD Internet Host Table Specification
+ RFC 1034: Domain Names - Concepts and Facilities
+ RFC 1123: Requirements for Internet Hosts -- Application
+ and Support
+ RFC 2782: A DNS RR for specifying the location of services
+ (DNS SRV)
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ typedef host {
+ type union {
+ type inet:ip-address;
+ type inet:domain-name;
+ }
+ description
+ "The host type represents either an IP address or a DNS
+ domain name.";
+ }
+
+ typedef uri {
+ type string;
+ description
+ "The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.";
+ reference
+ "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+ Group: Uniform Resource Identifiers (URIs), URLs,
+ and Uniform Resource Names (URNs): Clarifications
+ and Recommendations
+ RFC 5017: MIB Textual Conventions for Uniform Resource
+ Identifiers (URIs)";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-restconf-monitoring@2017-01-26.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-restconf-monitoring@2017-01-26.yang
new file mode 100644
index 0000000..55c3cb1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-restconf-monitoring@2017-01-26.yang
@@ -0,0 +1,149 @@
+module ietf-restconf-monitoring {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring";
+ prefix "rcmon";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ Author: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Author: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Author: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+
+ description
+ "This module contains monitoring information for the
+ RESTCONF protocol.
+
+ Copyright (c) 2017 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 8040; see
+ the RFC itself for full legal notices.";
+
+ revision 2017-01-26 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 8040: RESTCONF Protocol.";
+ }
+
+ container restconf-state {
+ config false;
+ description
+ "Contains RESTCONF protocol monitoring information.";
+
+ container capabilities {
+ description
+ "Contains a list of protocol capability URIs.";
+
+ leaf-list capability {
+ type inet:uri;
+ description
+ "A RESTCONF protocol capability URI.";
+ }
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description
+ "The stream name.";
+ reference
+ "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "Description of stream content.";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ default false;
+ description
+ "Indicates if replay buffer is supported for this stream.
+ If 'true', then the server MUST support the 'start-time'
+ and 'stop-time' query parameters for this stream.";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ when "../replay-support" {
+ description
+ "Only present if notification replay is supported.";
+ }
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ list access {
+ key encoding;
+ min-elements 1;
+ description
+ "The server will create an entry in this list for each
+ encoding format that is supported for this stream.
+ The media type 'text/event-stream' is expected
+ for all event streams. This list identifies the
+ subtypes supported for this stream.";
+
+ leaf encoding {
+ type string;
+ description
+ "This is the secondary encoding format within the
+ 'text/event-stream' encoding used by all streams.
+ The type 'xml' is supported for XML encoding.
+ The type 'json' is supported for JSON encoding.";
+ }
+
+ leaf location {
+ type inet:uri;
+ mandatory true;
+ description
+ "Contains a URL that represents the entry point
+ for establishing notification delivery via
+ server-sent events.";
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-yang-library@2016-06-21.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-yang-library@2016-06-21.yang
new file mode 100644
index 0000000..bc466ee
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-yang-library@2016-06-21.yang
@@ -0,0 +1,208 @@
+module ietf-yang-library {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-library";
+ prefix "yanglib";
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import ietf-inet-types {
+ prefix inet;
+ }
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+ WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+ WG Chair: Mahesh Jethanandani
+ <mailto:mjethanandani@gmail.com>
+ Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+ description
+ "This module contains monitoring information about the YANG
+ modules and submodules that are used within a YANG-based
+ server.
+ Copyright (c) 2016 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+ This version of this YANG module is part of RFC 7895; see
+ the RFC itself for full legal notices.";
+ revision 2016-06-21 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 7895: YANG Module Library.";
+ }
+ /*
+ * Typedefs
+ */
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.";
+ }
+ /*
+ * Groupings
+ */
+ grouping module-list {
+ description
+ "The module data structure is represented as a grouping
+ so it can be reused in configuration or another monitoring
+ data structure.";
+ grouping common-leafs {
+ description
+ "Common parameters for YANG modules and submodules.";
+ leaf name {
+ type yang:yang-identifier;
+ description
+ "The YANG module or submodule name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module or submodule revision date.
+ A zero-length string is used if no revision statement
+ is present in the YANG module or submodule.";
+ }
+ }
+ grouping schema-leaf {
+ description
+ "Common schema leaf parameter for modules and submodules.";
+ leaf schema {
+ type inet:uri;
+ description
+ "Contains a URL that represents the YANG schema
+ resource for this module or submodule.
+ This leaf will only be present if there is a URL
+ available for retrieval of the schema for this entry.";
+ }
+ }
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one revision of one module
+ currently supported by the server.";
+ uses common-leafs;
+ uses schema-leaf;
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server, regardless of whether they are
+ defined in the module or any included submodule.";
+ }
+ list deviation {
+ key "name revision";
+ description
+ "List of YANG deviation module names and revisions
+ used by this server to modify the conformance of
+ the module associated with this entry. Note that
+ the same module can be used for deviations for
+ multiple modules, so the same entry MAY appear
+ within multiple 'module' entries.
+ The deviation module MUST be present in the 'module'
+ list, with the same name and revision values.
+ The 'conformance-type' value will be 'implement' for
+ the deviation module.";
+ uses common-leafs;
+ }
+ leaf conformance-type {
+ type enumeration {
+ enum implement {
+ description
+ "Indicates that the server implements one or more
+ protocol-accessible objects defined in the YANG module
+ identified in this entry. This includes deviation
+ statements defined in the module.
+ For YANG version 1.1 modules, there is at most one
+ module entry with conformance type 'implement' for a
+ particular module name, since YANG 1.1 requires that,
+ at most, one revision of a module is implemented.
+ For YANG version 1 modules, there SHOULD NOT be more
+ than one module entry for a particular module name.";
+ }
+ enum import {
+ description
+ "Indicates that the server imports reusable definitions
+ from the specified revision of the module but does
+ not implement any protocol-accessible objects from
+ this revision.
+ Multiple module entries for the same module name MAY
+ exist. This can occur if multiple modules import the
+ same module but specify different revision dates in
+ the import statements.";
+ }
+ }
+ mandatory true;
+ description
+ "Indicates the type of conformance the server is claiming
+ for the YANG module identified by this entry.";
+ }
+ list submodule {
+ key "name revision";
+ description
+ "Each entry represents one submodule within the
+ parent module.";
+ uses common-leafs;
+ uses schema-leaf;
+ }
+ }
+ }
+ /*
+ * Operational state data nodes
+ */
+ container modules-state {
+ config false;
+ description
+ "Contains YANG module monitoring information.";
+ leaf module-set-id {
+ type string;
+ mandatory true;
+ description
+ "Contains a server-specific identifier representing
+ the current set of modules and submodules. The
+ server MUST change the value of this leaf if the
+ information represented by the 'module' list instances
+ has changed.";
+ }
+ uses module-list;
+ }
+ /*
+ * Notifications
+ */
+ notification yang-library-change {
+ description
+ "Generated when the set of modules and submodules supported
+ by the server has changed.";
+ leaf module-set-id {
+ type leafref {
+ path "/yanglib:modules-state/yanglib:module-set-id";
+ }
+ mandatory true;
+ description
+ "Contains the module-set-id value representing the
+ set of modules and submodules supported at the server at
+ the time the notification is generated.";
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-yang-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-yang-types.yang
new file mode 100644
index 0000000..c3f952c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/ietf-yang-types.yang
@@ -0,0 +1,417 @@
+ module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+
+
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined by the 'identifier'
+ rule in Section 12 of RFC 6020. An identifier must
+ start with an alphabetic character or an underscore
+ followed by an arbitrary sequence of alphabetic or
+ numeric characters, underscores, hyphens, or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lowercase or uppercase character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using the
+ time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually referring
+ to the notion of local time) uses the time-offset -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence happened.
+ The specific occurrence must be defined in the description
+ of any schema node defined using this type. When the specific
+ occurrence occurred prior to the last time the associated
+ timeticks attribute was zero, then the timestamp value is
+ zero. Note that this requires all timestamp values to be
+ reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/invoke-rpc-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/invoke-rpc-module.yang
new file mode 100644
index 0000000..e744818
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/invoke-rpc-module.yang
@@ -0,0 +1,30 @@
+module invoke-rpc-module {
+ namespace "invoke:rpc:module";
+
+ prefix "inrpcmod";
+
+ revision 2013-12-03 {
+
+ }
+
+ rpc rpc-test {
+ input {
+ container cont {
+ leaf lf {
+ type string;
+ }
+ }
+ }
+ output {
+ container cont-out {
+ leaf lf-out {
+ type string;
+ }
+ }
+ }
+ }
+
+ rpc rpc-noop {
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/json/rpc-input.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/json/rpc-input.json
new file mode 100644
index 0000000..2ba5f27
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/json/rpc-input.json
@@ -0,0 +1,7 @@
+{
+ "invoke-rpc-module:input" : {
+ "cont" : {
+ "lf" : "lf-test"
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/json/rpc-output.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/json/rpc-output.json
new file mode 100644
index 0000000..107f4c7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/json/rpc-output.json
@@ -0,0 +1,7 @@
+{
+ "invoke-rpc-module:output" : {
+ "cont-out" : {
+ "lf-out" : "lf-test"
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/xml/rpc-input.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/xml/rpc-input.xml
new file mode 100644
index 0000000..48fb557
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/xml/rpc-input.xml
@@ -0,0 +1,5 @@
+<input xmlns="invoke:rpc:module">
+ <cont>
+ <lf>lf-test</lf>
+ </cont>
+</input> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/xml/rpc-output.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/xml/rpc-output.xml
new file mode 100644
index 0000000..3b11eb8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/invoke-rpc/xml/rpc-output.xml
@@ -0,0 +1,5 @@
+<output xmlns="invoke:rpc:module">
+ <cont-out>
+ <lf-out>lf-test</lf-out>
+ </cont-out>
+</output> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/array-with-null.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/array-with-null.json
new file mode 100644
index 0000000..995b3c6
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/array-with-null.json
@@ -0,0 +1,5 @@
+{
+ "array-with-null-yang:cont": {
+ "lf":null
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/empty-data.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/empty-data.json
new file mode 100644
index 0000000..aa7142d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/empty-data.json
@@ -0,0 +1,6 @@
+{
+ "array-with-null-yang:cont": {
+ "lflst1":[],
+ "lflst2":[45]
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/empty-data1.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/empty-data1.json
new file mode 100644
index 0000000..b886fc9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/empty-data1.json
@@ -0,0 +1,5 @@
+{
+ "cont": {
+ "lf":
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/identity-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/identity-module.yang
new file mode 100644
index 0000000..09a34c5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/identity-module.yang
@@ -0,0 +1,10 @@
+module identity-module {
+ namespace "identity:module";
+
+ prefix "idemod";
+ revision 2013-12-02 {
+ }
+
+ identity iden {
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/identityref-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/identityref-module.yang
new file mode 100644
index 0000000..80ec396
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/identityref-module.yang
@@ -0,0 +1,39 @@
+module identityref-module {
+ namespace "identityref:module";
+
+ prefix "iderefmod";
+
+ import identity-module {prefix idemo; revision-date 2013-12-02; }
+
+ revision 2013-12-02 {
+ }
+
+ identity iden_local {
+ }
+
+ container cont {
+ container cont1 {
+ leaf lf11 {
+ type identityref {
+ base "idemo:iden";
+ }
+ }
+ leaf lf12 {
+ type identityref {
+ base "iden_local";
+ }
+ }
+ leaf lf13 {
+ type identityref {
+ base "iden_local";
+ }
+ }
+ leaf lf14 {
+ type identityref {
+ base "iden_local";
+ }
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/json/data.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/json/data.json
new file mode 100644
index 0000000..88cd6b4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/identityref/json/data.json
@@ -0,0 +1,10 @@
+{
+ "identityref:cont":{
+ "cont1":{
+ "lf11":"identity-module:iden",
+ "lf12":"identityref-module:iden_local",
+ "identityref-module:lf13":"identityref-module:iden_local",
+ "identityref-module:lf14":"identity-module:iden"
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/invalid-uri-character-in-value.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/invalid-uri-character-in-value.json
new file mode 100644
index 0000000..545f99b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/invalid-uri-character-in-value.json
@@ -0,0 +1,6 @@
+{
+ "array-with-null-yang:cont":{
+ "lf1":"module<Name:value lf1",
+ "lf2":"module>Name:value lf2"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/augment-leafref-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/augment-leafref-module.yang
new file mode 100644
index 0000000..8a55e43
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/augment-leafref-module.yang
@@ -0,0 +1,18 @@
+module augment-leafref-module {
+ namespace "augment:leafref:module";
+
+ prefix "auglfrfmo";
+ revision 2014-12-16;
+
+ typedef leafreftype {
+ type leafref {
+ path "/auglfrfmo:cont/auglfrfmo:lf3";
+ }
+ }
+
+ container cont {
+ leaf lf3 {
+ type string;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/json/data.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/json/data.json
new file mode 100644
index 0000000..df5bcef
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/json/data.json
@@ -0,0 +1,7 @@
+{
+ "leafref-module:cont":{
+ "lf1":121,
+ "lf2":121,
+ "lf4":"pcc://39.39.39.39"
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/leafref-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/leafref-module.yang
new file mode 100644
index 0000000..9b124a0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/leafref/leafref-module.yang
@@ -0,0 +1,24 @@
+module leafref-module {
+ namespace "leafref:module";
+
+ prefix "lfrfmo";
+
+ import augment-leafref-module {prefix augleafref; revision-date 2014-12-16;}
+ revision 2013-11-18 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type int32;
+ }
+ leaf lf2 {
+ type leafref {
+ path "/cont/lf1";
+ }
+ }
+ leaf lf4 {
+ type augleafref:leafreftype;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/multiple-items-in-list.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/multiple-items-in-list.json
new file mode 100644
index 0000000..2131744
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/multiple-items-in-list.json
@@ -0,0 +1,26 @@
+{
+ "multiple-items-yang:lst":[
+ {
+ "lst1": [
+ {
+ "lf11":"lf11_1"
+ },
+ {
+ "lflst11":[
+ 45
+ ]
+ },
+ {
+ "cont11":{
+ }
+ },
+ {
+ "lst11":[
+ {
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/multiple-leaflist-items.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/multiple-leaflist-items.json
new file mode 100644
index 0000000..c1f5d1e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/multiple-leaflist-items.json
@@ -0,0 +1,5 @@
+{
+ "simple-list-yang1:lst": {
+ "lflst1":[45,55,66]
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-container-yang/simple-container.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-container-yang/simple-container.yang
new file mode 100644
index 0000000..493101c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-container-yang/simple-container.yang
@@ -0,0 +1,20 @@
+module simple-container-yang {
+ namespace "simple:container:yang";
+
+ prefix "smpdtp";
+ revision 2013-11-12 {
+ }
+
+ container cont {
+ container cont1 {
+ }
+ list lst1 {
+ }
+ leaf-list lflst1 {
+ type string;
+ }
+ leaf lf1 {
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-container.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-container.json
new file mode 100644
index 0000000..28d244d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-container.json
@@ -0,0 +1,15 @@
+{
+ "simple-container-yang:cont":{
+ "cont1":{
+ },
+ "lst1": [
+ {
+ }
+ ],
+ "lflst1":[
+ "lflst1_1",
+ "lflst1_2"
+ ],
+ "lf1":"lf1"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/1/simple-list1.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/1/simple-list1.yang
new file mode 100644
index 0000000..0ce8ea4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/1/simple-list1.yang
@@ -0,0 +1,20 @@
+module simple-list-yang1 {
+ namespace "simple:list:yang1";
+
+ prefix "smplstyg";
+ revision 2013-11-12 {
+ }
+
+ list lst {
+ container cont1 {
+ }
+ list lst1 {
+ }
+ leaf-list lflst1 {
+ type string;
+ }
+ leaf lf1 {
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/2/simple-list2.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/2/simple-list2.yang
new file mode 100644
index 0000000..0872a47
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/2/simple-list2.yang
@@ -0,0 +1,20 @@
+module simple-list-yang2 {
+ namespace "simple:list:yang2";
+
+ prefix "smplstyg";
+ revision 2013-11-12 {
+ }
+
+ list lst {
+ container cont1 {
+ }
+ list lst1 {
+ }
+ leaf-list lflst1 {
+ type string;
+ }
+ leaf lf1 {
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/3/multiple-items.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/3/multiple-items.yang
new file mode 100644
index 0000000..dcc17d5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/3/multiple-items.yang
@@ -0,0 +1,24 @@
+module multiple-items-yang {
+ namespace "multiple:items:yang";
+
+ prefix "mltitmsyg";
+ revision 2013-11-12 {
+ }
+
+ list lst {
+ list lst1 {
+ leaf lf11{
+ type string;
+ }
+ leaf-list lflst11{
+ type string;
+ }
+ container cont11{
+
+ }
+ list lst11{
+
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/4/array-with-null.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/4/array-with-null.yang
new file mode 100644
index 0000000..869e406
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list-yang/4/array-with-null.yang
@@ -0,0 +1,26 @@
+module array-with-null-yang {
+ namespace "array:with:null:yang";
+
+ prefix "arwnlyn";
+ revision 2013-11-12 {
+ }
+
+ container cont{
+ leaf lf{
+ type empty;
+ }
+ leaf lf1{
+ type string;
+ }
+ leaf lf2{
+ type string;
+ }
+ leaf-list lflst1{
+ type empty;
+ }
+
+ leaf-list lflst2{
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list.json
new file mode 100644
index 0000000..76a0190
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/simple-list.json
@@ -0,0 +1,17 @@
+{
+ "simple-list-yang1:lst":[
+ {
+ "cont1":{
+ },
+ "lst1": [
+ {
+ }
+ ],
+ "lflst1":[
+ "lflst1_1",
+ "lflst1_2"
+ ],
+ "lf1":"lf1"
+ }
+ ]
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/unsupported-json-format.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/unsupported-json-format.json
new file mode 100644
index 0000000..abc6267
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/unsupported-json-format.json
@@ -0,0 +1 @@
+fffff \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level1.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level1.json
new file mode 100644
index 0000000..88baef3
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level1.json
@@ -0,0 +1,8 @@
+{
+ "wrong":[
+ {
+ },
+ {
+ }
+ ]
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level2.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level2.json
new file mode 100644
index 0000000..c567273
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level2.json
@@ -0,0 +1,9 @@
+{
+
+ "simple-list-yang1:lst": {
+ },
+ "lst1":[
+ {
+ }
+ ]
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level3.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level3.json
new file mode 100644
index 0000000..7288969
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/json-to-nn/wrong-top-level3.json
@@ -0,0 +1,3 @@
+{
+ "lf":"hello"
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/augmented-jukebox@2016-05-05.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/augmented-jukebox@2016-05-05.yang
new file mode 100644
index 0000000..abbd5d0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/augmented-jukebox@2016-05-05.yang
@@ -0,0 +1,16 @@
+module augmented-jukebox {
+
+ namespace "http://example.com/ns/augmented-jukebox";
+ prefix "augmented-jbox";
+
+ revision "2016-05-05" {
+ description "Initial version.";
+ }
+
+ import example-jukebox {prefix jbox; revision-date "2015-04-04";}
+
+ augment "/jbox:jukebox" {
+ container augmented-library {
+ }
+ }
+ } \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/example-jukebox@2015-04-04.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/example-jukebox@2015-04-04.yang
new file mode 100644
index 0000000..ddaa602
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/example-jukebox@2015-04-04.yang
@@ -0,0 +1,243 @@
+module example-jukebox {
+
+ namespace "http://example.com/ns/example-jukebox";
+ prefix "jbox";
+
+ organization "Example, Inc.";
+ contact "support at example.com";
+ description "Example Jukebox Data Model Module";
+ revision "2015-04-04" {
+ description "Initial version.";
+ reference "example.com document 1-4673";
+ }
+
+ identity genre {
+ description "Base for all genre types";
+ }
+
+ // abbreviated list of genre classifications
+ identity alternative {
+ base genre;
+ description "Alternative music";
+ }
+ identity blues {
+ base genre;
+ description "Blues music";
+ }
+ identity country {
+ base genre;
+ description "Country music";
+ }
+ identity jazz {
+ base genre;
+ description "Jazz music";
+ }
+ identity pop {
+ base genre;
+ description "Pop music";
+ }
+ identity rock {
+ base genre;
+ description "Rock music";
+ }
+
+ container jukebox {
+ presence
+ "An empty container indicates that the jukebox
+ service is available";
+
+ description
+ "Represents a jukebox resource, with a library, playlists,
+ and a play operation.";
+
+ container library {
+
+ description "Represents the jukebox library resource.";
+
+ list artist {
+ key name;
+
+ description
+ "Represents one artist resource within the
+ jukebox library resource.";
+
+ leaf name {
+ type string {
+ length "1 .. max";
+ }
+ description "The name of the artist.";
+ }
+
+ list album {
+ key name;
+
+ description
+ "Represents one album resource within one
+ artist resource, within the jukebox library.";
+
+ leaf name {
+ type string {
+ length "1 .. max";
+ }
+ description "The name of the album.";
+ }
+
+ leaf genre {
+ type identityref { base genre; }
+ description
+ "The genre identifying the type of music on
+ the album.";
+ }
+
+ leaf year {
+ type uint16 {
+ range "1900 .. max";
+ }
+ description "The year the album was released";
+ }
+
+ container admin {
+ description
+ "Administrative information for the album.";
+
+ leaf label {
+ type string;
+ description "The label that released the album.";
+ }
+ leaf catalogue-number {
+ type string;
+ description "The album's catalogue number.";
+ }
+ }
+
+ list song {
+ key name;
+
+ description
+ "Represents one song resource within one
+ album resource, within the jukebox library.";
+
+ leaf name {
+ type string {
+ length "1 .. max";
+ }
+ description "The name of the song";
+ }
+ leaf location {
+ type string;
+ mandatory true;
+ description
+ "The file location string of the
+ media file for the song";
+ }
+ leaf format {
+ type string;
+ description
+ "An identifier string for the media type
+ for the file associated with the
+ 'location' leaf for this entry.";
+ }
+ leaf length {
+ type uint32;
+ units "seconds";
+ description
+ "The duration of this song in seconds.";
+ }
+ } // end list 'song'
+ } // end list 'album'
+ } // end list 'artist'
+
+ leaf artist-count {
+ type uint32;
+ units "songs";
+ config false;
+ description "Number of artists in the library";
+ }
+ leaf album-count {
+ type uint32;
+ units "albums";
+ config false;
+ description "Number of albums in the library";
+ }
+ leaf song-count {
+ type uint32;
+ units "songs";
+ config false;
+ description "Number of songs in the library";
+ }
+ } // end library
+
+ list playlist {
+ key name;
+
+ description
+ "Example configuration data resource";
+
+ leaf name {
+ type string;
+ description
+ "The name of the playlist.";
+ }
+ leaf description {
+ type string;
+ description
+ "A comment describing the playlist.";
+ }
+
+ list song {
+ key index;
+ ordered-by user;
+
+ description
+ "Example nested configuration data resource";
+
+ leaf index { // not really needed
+ type uint32;
+ description
+ "An arbitrary integer index for this playlist song.";
+ }
+ leaf id {
+ type leafref {
+ path "/jbox:jukebox/jbox:library/jbox:artist/" +
+ "jbox:album/jbox:song/jbox:name";
+ }
+ mandatory true;
+ description
+ "Song identifier. Must identify an instance of
+ /jukebox/library/artist/album/song/name.";
+ }
+ }
+ }
+
+ container player {
+ description
+ "Represents the jukebox player resource.";
+
+ leaf gap {
+ type decimal64 {
+ fraction-digits 1;
+ range "0.0 .. 2.0";
+ }
+ units "tenths of seconds";
+ description "Time gap between each song";
+ }
+ }
+ }
+
+ rpc play {
+ description "Control function for the jukebox player";
+ input {
+ leaf playlist {
+ type string;
+ mandatory true;
+ description "playlist name";
+ }
+
+ leaf song-number {
+ type uint32;
+ mandatory true;
+ description "Song number in playlist to play";
+ }
+ }
+ }
+ } \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-inet-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-inet-types.yang
new file mode 100644
index 0000000..de20feb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-inet-types.yang
@@ -0,0 +1,418 @@
+ module ietf-inet-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+ prefix "inet";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ typedef ip-version {
+ type enumeration {
+ enum unknown {
+ value "0";
+ description
+ "An unknown or unspecified version of the Internet protocol.";
+ }
+ enum ipv4 {
+ value "1";
+ description
+ "The IPv4 protocol as defined in RFC 791.";
+ }
+ enum ipv6 {
+ value "2";
+ description
+ "The IPv6 protocol as defined in RFC 2460.";
+ }
+ }
+ description
+ "This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.";
+ reference
+ "RFC 791: Internet Protocol
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ typedef dscp {
+ type uint8 {
+ range "0..63";
+ }
+ description
+ "The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.";
+ reference
+ "RFC 3289: Management Information Base for the Differentiated
+ Services Architecture
+ RFC 2474: Definition of the Differentiated Services Field
+ (DS Field) in the IPv4 and IPv6 Headers
+ RFC 2780: IANA Allocation Guidelines For Values In
+ the Internet Protocol and Related Headers";
+ }
+
+ typedef ipv6-flow-label {
+ type uint32 {
+ range "0..1048575";
+ }
+ description
+ "The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.";
+ reference
+ "RFC 3595: Textual Conventions for IPv6 Flow Label
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+ }
+
+ typedef port-number {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.";
+ reference
+ "RFC 768: User Datagram Protocol
+ RFC 793: Transmission Control Protocol
+ RFC 4960: Stream Control Transmission Protocol
+ RFC 4340: Datagram Congestion Control Protocol (DCCP)
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of autonomous system related types ***/
+
+ typedef as-number {
+ type uint32;
+ description
+ "The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.";
+ reference
+ "RFC 1930: Guidelines for creation, selection, and registration
+ of an Autonomous System (AS)
+ RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+ RFC 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ typedef ip-address {
+ type union {
+ type inet:ipv4-address;
+ type inet:ipv6-address;
+ }
+ description
+ "The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '(%[\p{N}\p{L}]+)?';
+ }
+ description
+ "The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format";
+ }
+
+ typedef ipv6-address {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(%[\p{N}\p{L}]+)?';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(%.+)?';
+ }
+ description
+ "The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture
+ RFC 4007: IPv6 Scoped Address Architecture
+ RFC 5952: A Recommendation for IPv6 Address Text Representation";
+ }
+
+ typedef ip-prefix {
+ type union {
+ type inet:ipv4-prefix;
+ type inet:ipv6-prefix;
+ }
+ description
+ "The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-prefix {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+ }
+ description
+ "The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.";
+ }
+
+ typedef ipv6-prefix {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(/.+)';
+ }
+ description
+ "The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** collection of domain name and URI types ***/
+
+ typedef domain-name {
+ type string {
+ pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ + '|\.';
+ length "1..253";
+ }
+ description
+ "The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492";
+ reference
+ "RFC 952: DoD Internet Host Table Specification
+ RFC 1034: Domain Names - Concepts and Facilities
+ RFC 1123: Requirements for Internet Hosts -- Application
+ and Support
+ RFC 2782: A DNS RR for specifying the location of services
+ (DNS SRV)
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ typedef host {
+ type union {
+ type inet:ip-address;
+ type inet:domain-name;
+ }
+ description
+ "The host type represents either an IP address or a DNS
+ domain name.";
+ }
+
+ typedef uri {
+ type string;
+ description
+ "The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.";
+ reference
+ "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+ Group: Uniform Resource Identifiers (URIs), URLs,
+ and Uniform Resource Names (URNs): Clarifications
+ and Recommendations
+ RFC 5017: MIB Textual Conventions for Uniform Resource
+ Identifiers (URIs)";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-restconf-monitoring@2017-01-26.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-restconf-monitoring@2017-01-26.yang
new file mode 100644
index 0000000..55c3cb1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-restconf-monitoring@2017-01-26.yang
@@ -0,0 +1,149 @@
+module ietf-restconf-monitoring {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring";
+ prefix "rcmon";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ Author: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Author: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Author: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+
+ description
+ "This module contains monitoring information for the
+ RESTCONF protocol.
+
+ Copyright (c) 2017 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 8040; see
+ the RFC itself for full legal notices.";
+
+ revision 2017-01-26 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 8040: RESTCONF Protocol.";
+ }
+
+ container restconf-state {
+ config false;
+ description
+ "Contains RESTCONF protocol monitoring information.";
+
+ container capabilities {
+ description
+ "Contains a list of protocol capability URIs.";
+
+ leaf-list capability {
+ type inet:uri;
+ description
+ "A RESTCONF protocol capability URI.";
+ }
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description
+ "The stream name.";
+ reference
+ "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "Description of stream content.";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ default false;
+ description
+ "Indicates if replay buffer is supported for this stream.
+ If 'true', then the server MUST support the 'start-time'
+ and 'stop-time' query parameters for this stream.";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ when "../replay-support" {
+ description
+ "Only present if notification replay is supported.";
+ }
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ list access {
+ key encoding;
+ min-elements 1;
+ description
+ "The server will create an entry in this list for each
+ encoding format that is supported for this stream.
+ The media type 'text/event-stream' is expected
+ for all event streams. This list identifies the
+ subtypes supported for this stream.";
+
+ leaf encoding {
+ type string;
+ description
+ "This is the secondary encoding format within the
+ 'text/event-stream' encoding used by all streams.
+ The type 'xml' is supported for XML encoding.
+ The type 'json' is supported for JSON encoding.";
+ }
+
+ leaf location {
+ type inet:uri;
+ mandatory true;
+ description
+ "Contains a URL that represents the entry point
+ for establishing notification delivery via
+ server-sent events.";
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-yang-library@2016-06-21.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-yang-library@2016-06-21.yang
new file mode 100644
index 0000000..bc466ee
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-yang-library@2016-06-21.yang
@@ -0,0 +1,208 @@
+module ietf-yang-library {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-library";
+ prefix "yanglib";
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import ietf-inet-types {
+ prefix inet;
+ }
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+ WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+ WG Chair: Mahesh Jethanandani
+ <mailto:mjethanandani@gmail.com>
+ Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+ description
+ "This module contains monitoring information about the YANG
+ modules and submodules that are used within a YANG-based
+ server.
+ Copyright (c) 2016 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+ This version of this YANG module is part of RFC 7895; see
+ the RFC itself for full legal notices.";
+ revision 2016-06-21 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 7895: YANG Module Library.";
+ }
+ /*
+ * Typedefs
+ */
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.";
+ }
+ /*
+ * Groupings
+ */
+ grouping module-list {
+ description
+ "The module data structure is represented as a grouping
+ so it can be reused in configuration or another monitoring
+ data structure.";
+ grouping common-leafs {
+ description
+ "Common parameters for YANG modules and submodules.";
+ leaf name {
+ type yang:yang-identifier;
+ description
+ "The YANG module or submodule name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module or submodule revision date.
+ A zero-length string is used if no revision statement
+ is present in the YANG module or submodule.";
+ }
+ }
+ grouping schema-leaf {
+ description
+ "Common schema leaf parameter for modules and submodules.";
+ leaf schema {
+ type inet:uri;
+ description
+ "Contains a URL that represents the YANG schema
+ resource for this module or submodule.
+ This leaf will only be present if there is a URL
+ available for retrieval of the schema for this entry.";
+ }
+ }
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one revision of one module
+ currently supported by the server.";
+ uses common-leafs;
+ uses schema-leaf;
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server, regardless of whether they are
+ defined in the module or any included submodule.";
+ }
+ list deviation {
+ key "name revision";
+ description
+ "List of YANG deviation module names and revisions
+ used by this server to modify the conformance of
+ the module associated with this entry. Note that
+ the same module can be used for deviations for
+ multiple modules, so the same entry MAY appear
+ within multiple 'module' entries.
+ The deviation module MUST be present in the 'module'
+ list, with the same name and revision values.
+ The 'conformance-type' value will be 'implement' for
+ the deviation module.";
+ uses common-leafs;
+ }
+ leaf conformance-type {
+ type enumeration {
+ enum implement {
+ description
+ "Indicates that the server implements one or more
+ protocol-accessible objects defined in the YANG module
+ identified in this entry. This includes deviation
+ statements defined in the module.
+ For YANG version 1.1 modules, there is at most one
+ module entry with conformance type 'implement' for a
+ particular module name, since YANG 1.1 requires that,
+ at most, one revision of a module is implemented.
+ For YANG version 1 modules, there SHOULD NOT be more
+ than one module entry for a particular module name.";
+ }
+ enum import {
+ description
+ "Indicates that the server imports reusable definitions
+ from the specified revision of the module but does
+ not implement any protocol-accessible objects from
+ this revision.
+ Multiple module entries for the same module name MAY
+ exist. This can occur if multiple modules import the
+ same module but specify different revision dates in
+ the import statements.";
+ }
+ }
+ mandatory true;
+ description
+ "Indicates the type of conformance the server is claiming
+ for the YANG module identified by this entry.";
+ }
+ list submodule {
+ key "name revision";
+ description
+ "Each entry represents one submodule within the
+ parent module.";
+ uses common-leafs;
+ uses schema-leaf;
+ }
+ }
+ }
+ /*
+ * Operational state data nodes
+ */
+ container modules-state {
+ config false;
+ description
+ "Contains YANG module monitoring information.";
+ leaf module-set-id {
+ type string;
+ mandatory true;
+ description
+ "Contains a server-specific identifier representing
+ the current set of modules and submodules. The
+ server MUST change the value of this leaf if the
+ information represented by the 'module' list instances
+ has changed.";
+ }
+ uses module-list;
+ }
+ /*
+ * Notifications
+ */
+ notification yang-library-change {
+ description
+ "Generated when the set of modules and submodules supported
+ by the server has changed.";
+ leaf module-set-id {
+ type leafref {
+ path "/yanglib:modules-state/yanglib:module-set-id";
+ }
+ mandatory true;
+ description
+ "Contains the module-set-id value representing the
+ set of modules and submodules supported at the server at
+ the time the notification is generated.";
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-yang-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-yang-types.yang
new file mode 100644
index 0000000..c3f952c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/jukebox/ietf-yang-types.yang
@@ -0,0 +1,417 @@
+ module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+
+
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined by the 'identifier'
+ rule in Section 12 of RFC 6020. An identifier must
+ start with an alphabetic character or an underscore
+ followed by an arbitrary sequence of alphabetic or
+ numeric characters, underscores, hyphens, or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lowercase or uppercase character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using the
+ time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually referring
+ to the notion of local time) uses the time-offset -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence happened.
+ The specific occurrence must be defined in the description
+ of any schema node defined using this type. When the specific
+ occurrence occurred prior to the last time the associated
+ timeticks attribute was zero, then the timestamp value is
+ zero. Note that this requires all timestamp values to be
+ reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/json/jsondata.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/json/jsondata.json
new file mode 100644
index 0000000..f4a435e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/json/jsondata.json
@@ -0,0 +1,8 @@
+{
+ "leafref-module:cont" : {
+ "lf4" : "/referenced-module:cont/referenced-module:lf1",
+ "lf2" : "/leafref-module:cont/leafref-module:lf1",
+ "lf3" : "/leafref-module:cont/leafref-module:lf2",
+ "lf5" : "/leafref-module:cont/leafref-module:lf3"
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/xml/xmldata.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/xml/xmldata.xml
new file mode 100644
index 0000000..1b5ce83
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/xml/xmldata.xml
@@ -0,0 +1,6 @@
+<cont xmlnsa="leafref:module">
+ <lf4 xmlns:nsa="referenced:module">/nsa:cont/nsa:lf1</lf4>
+ <lf2 xmlns:nsa="leafref:module">/nsa:cont/nsa:lf1</lf2>
+ <lf3 xmlns:ns="leafref:module">/ns:cont/ns:lf2</lf3>
+ <lf5 xmlns:nsa="leafref:module">/nsa:cont/nsa:lf3</lf5>
+</cont>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/yang/leafref-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/yang/leafref-module.yang
new file mode 100644
index 0000000..9675b79
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/yang/leafref-module.yang
@@ -0,0 +1,54 @@
+module leafref-module {
+ namespace "leafref:module";
+
+
+ prefix "lfrfmodule";
+
+ import referenced-module { prefix refmod; revision-date 2014-04-17;}
+
+
+ revision 2014-04-17 {
+ }
+
+
+ container cont {
+ leaf lf1 {
+ type instance-identifier;
+ }
+
+ leaf lf2 {
+ type leafref {
+ path "../lf1";
+ }
+ }
+
+ leaf lf3 {
+ type leafref {
+ path "/refmod:cont/refmod:lf1";
+ }
+ }
+
+ leaf lf4 {
+ type leafref {
+ path "/cont/lf1";
+ }
+ }
+
+ leaf lf5 {
+ type leafref {
+ path "../lf1";
+ }
+ }
+
+ list lst-with-lfref-key {
+ key "lfref-key";
+
+ leaf lfref-key {
+ type leafref {
+ path "/refmod:cont/refmod:id-ref";
+ }
+ }
+ }
+
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/yang/referenced-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/yang/referenced-module.yang
new file mode 100644
index 0000000..05dd123
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/leafref/yang/referenced-module.yang
@@ -0,0 +1,23 @@
+module referenced-module {
+ namespace "referenced:module";
+
+ prefix "refmodule";
+ revision 2014-04-17 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type instance-identifier;
+ }
+
+ leaf id-ref {
+ type leafref {
+ path "../../id";
+ }
+ }
+ }
+
+ leaf id {
+ type string;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-create.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-create.json
new file mode 100644
index 0000000..bc1cf52
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-create.json
@@ -0,0 +1,55 @@
+{
+ "notification": {
+ "data-changed-notification": {
+ "data-change-event": [
+ {
+ "data": {
+ "my-leaf11": {
+ "content": "Jed",
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "created",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf11"
+ },
+ {
+ "data": {
+ "name": {
+ "content": "Althea",
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "created",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:name"
+ },
+ {
+ "data": {
+ "patch-cont": {
+ "my-list1": {
+ "my-leaf11": "Jed",
+ "name": "Althea"
+ },
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "created",
+ "path": "/instance-identifier-patch-module:patch-cont"
+ },
+ {
+ "data": {
+ "my-list1": {
+ "my-leaf11": "Jed",
+ "name": "Althea",
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "created",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']"
+ }
+ ],
+ "xmlns": "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"
+ },
+ "eventTime": "2017-09-17T13:32:03.586+03:00",
+ "xmlns": "urn:ietf:params:xml:ns:netconf:notification:1.0"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-del.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-del.json
new file mode 100644
index 0000000..dbadab2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-del.json
@@ -0,0 +1,31 @@
+{
+ "notification": {
+ "data-changed-notification": {
+ "data-change-event": [
+ {
+ "operation": "deleted",
+ "path": "/instance-identifier-patch-module:patch-cont"
+ },
+ {
+ "operation": "deleted",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']"
+ },
+ {
+ "operation": "deleted",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:name"
+ },
+ {
+ "operation": "deleted",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf12"
+ },
+ {
+ "operation": "deleted",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf11"
+ }
+ ],
+ "xmlns": "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"
+ },
+ "eventTime": "2017-09-17T14:18:53.404+03:00",
+ "xmlns": "urn:ietf:params:xml:ns:netconf:notification:1.0"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-create.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-create.json
new file mode 100644
index 0000000..52be56a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-create.json
@@ -0,0 +1,31 @@
+{
+ "notification": {
+ "data-changed-notification": {
+ "data-change-event": [
+ {
+ "data": {
+ "my-leaf11": {
+ "content": "Jed",
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "created",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf11"
+ },
+ {
+ "data": {
+ "name": {
+ "content": "Althea",
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "created",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:name"
+ }
+ ],
+ "xmlns": "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"
+ },
+ "eventTime": "2017-09-17T11:23:10.323+03:00",
+ "xmlns": "urn:ietf:params:xml:ns:netconf:notification:1.0"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-del.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-del.json
new file mode 100644
index 0000000..5d9e9f1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-del.json
@@ -0,0 +1,23 @@
+{
+ "notification": {
+ "data-changed-notification": {
+ "data-change-event": [
+ {
+ "operation": "deleted",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf11"
+ },
+ {
+ "operation": "deleted",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:name"
+ },
+ {
+ "operation": "deleted",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf12"
+ }
+ ],
+ "xmlns": "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"
+ },
+ "eventTime": "2017-09-18T15:30:16.099+03:00",
+ "xmlns": "urn:ietf:params:xml:ns:netconf:notification:1.0"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-update.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-update.json
new file mode 100644
index 0000000..ffef660
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-update.json
@@ -0,0 +1,31 @@
+{
+ "notification": {
+ "data-changed-notification": {
+ "data-change-event": [
+ {
+ "data": {
+ "my-leaf12": {
+ "content": "Bertha",
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "created",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf12"
+ },
+ {
+ "data": {
+ "name": {
+ "content": "Althea",
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "updated",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:name"
+ }
+ ],
+ "xmlns": "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"
+ },
+ "eventTime": "2017-09-18T14:20:54.82+03:00",
+ "xmlns": "urn:ietf:params:xml:ns:netconf:notification:1.0"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-update.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-update.json
new file mode 100644
index 0000000..b2957ea
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-update.json
@@ -0,0 +1,57 @@
+{
+ "notification": {
+ "data-changed-notification": {
+ "data-change-event": [
+ {
+ "data": {
+ "patch-cont": {
+ "my-list1": {
+ "my-leaf11": "Jed",
+ "my-leaf12": "Bertha",
+ "name": "Althea"
+ },
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "updated",
+ "path": "/instance-identifier-patch-module:patch-cont"
+ },
+ {
+ "data": {
+ "my-list1": {
+ "my-leaf11": "Jed",
+ "my-leaf12": "Bertha",
+ "name": "Althea",
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "updated",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']"
+ },
+ {
+ "data": {
+ "my-leaf12": {
+ "content": "Bertha",
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "created",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf12"
+ },
+ {
+ "data": {
+ "name": {
+ "content": "Althea",
+ "xmlns": "instance:identifier:patch:module"
+ }
+ },
+ "operation": "updated",
+ "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:name"
+ }
+ ],
+ "xmlns": "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"
+ },
+ "eventTime": "2017-09-18T15:52:25.213+03:00",
+ "xmlns": "urn:ietf:params:xml:ns:netconf:notification:1.0"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-create.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-create.json
new file mode 100644
index 0000000..6e4dadc
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-create.json
@@ -0,0 +1,13 @@
+{
+ "notification":{
+ "xmlns":"urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "data-changed-notification":{
+ "xmlns":"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "data-change-event":{
+ "path":"/instance-identifier-patch-module:patch-cont",
+ "operation":"created"
+ }
+ },
+ "eventTime":"2020-05-31T18:45:05.132101+05:30"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-del.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-del.json
new file mode 100644
index 0000000..dc3f739
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-del.json
@@ -0,0 +1,13 @@
+{
+ "notification":{
+ "xmlns":"urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "data-changed-notification":{
+ "xmlns":"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "data-change-event":{
+ "path":"/instance-identifier-patch-module:patch-cont",
+ "operation":"deleted"
+ }
+ },
+ "eventTime":"2020-05-31T18:45:05.132101+05:30"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-update.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-update.json
new file mode 100644
index 0000000..c22c956
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-without-data-update.json
@@ -0,0 +1,13 @@
+{
+ "notification":{
+ "xmlns":"urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "data-changed-notification":{
+ "xmlns":"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "data-change-event":{
+ "path":"/instance-identifier-patch-module:patch-cont",
+ "operation":"updated"
+ }
+ },
+ "eventTime":"2020-05-31T18:45:05.132101+05:30"
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/iana-if-type.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/iana-if-type.yang
new file mode 100644
index 0000000..7bd0003
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/iana-if-type.yang
@@ -0,0 +1,1517 @@
+module iana-if-type {
+ namespace "urn:ietf:params:xml:ns:yang:iana-if-type";
+ prefix ianaift;
+
+ organization "IANA";
+ contact
+ " Internet Assigned Numbers Authority
+
+ Postal: ICANN
+ 4676 Admiralty Way, Suite 330
+ Marina del Rey, CA 90292
+
+ Tel: +1 310 823 9358
+ E-Mail: iana&iana.org";
+ description
+ "This YANG module defines the iana-if-type typedef, which
+ contains YANG definitions for IANA-registered interface types.
+
+ This YANG module is maintained by IANA, and reflects the
+ 'ifType definitions' registry.
+
+ The latest revision of this YANG module can be obtained from
+ the IANA web site.
+
+ Copyright (c) 2011 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-07-04 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: IANA Interface Type YANG Module";
+ }
+
+ typedef iana-if-type {
+ type enumeration {
+ enum "other" {
+ value 1;
+ description
+ "None of the following";
+ }
+ enum "regular1822" {
+ value 2;
+ }
+ enum "hdh1822" {
+ value 3;
+ }
+ enum "ddnX25" {
+ value 4;
+ }
+ enum "rfc877x25" {
+ value 5;
+ reference
+ "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer";
+ }
+ enum "ethernetCsmacd" {
+ value 6;
+ description
+ "For all ethernet-like interfaces, regardless of speed,
+ as per RFC3635.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "iso88023Csmacd" {
+ value 7;
+ status deprecated;
+ description
+ "Deprecated via RFC3635.
+ Use ethernetCsmacd(6) instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "iso88024TokenBus" {
+ value 8;
+ }
+ enum "iso88025TokenRing" {
+ value 9;
+ }
+ enum "iso88026Man" {
+ value 10;
+ }
+ enum "starLan" {
+ value 11;
+ status deprecated;
+ description
+ "Deprecated via RFC3635.
+ Use ethernetCsmacd(6) instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "proteon10Mbit" {
+ value 12;
+ }
+ enum "proteon80Mbit" {
+ value 13;
+ }
+ enum "hyperchannel" {
+ value 14;
+ }
+ enum "fddi" {
+ value 15;
+ reference
+ "RFC 1512 - FDDI Management Information Base";
+ }
+ enum "lapb" {
+ value 16;
+ reference
+ "RFC 1381 - SNMP MIB Extension for X.25 LAPB";
+ }
+ enum "sdlc" {
+ value 17;
+ }
+ enum "ds1" {
+ value 18;
+ description
+ "DS1-MIB";
+ reference
+ "RFC 4805 - Definitions of Managed Objects for the
+ DS1, J1, E1, DS2, and E2 Interface Types";
+ }
+ enum "e1" {
+ value 19;
+ status obsolete;
+ description
+ "Obsolete see DS1-MIB";
+ reference
+ "RFC 4805 - Definitions of Managed Objects for the
+ DS1, J1, E1, DS2, and E2 Interface Types";
+ }
+ enum "basicISDN" {
+ value 20;
+ description
+ "see also RFC2127";
+ }
+ enum "primaryISDN" {
+ value 21;
+ }
+ enum "propPointToPointSerial" {
+ value 22;
+ description
+ "proprietary serial";
+ }
+ enum "ppp" {
+ value 23;
+ }
+ enum "softwareLoopback" {
+ value 24;
+ }
+ enum "eon" {
+ value 25;
+ description
+ "CLNP over IP";
+ }
+ enum "ethernet3Mbit" {
+ value 26;
+ }
+ enum "nsip" {
+ value 27;
+ description
+ "XNS over IP";
+ }
+ enum "slip" {
+ value 28;
+ description
+ "generic SLIP";
+ }
+ enum "ultra" {
+ value 29;
+ description
+ "ULTRA technologies";
+ }
+ enum "ds3" {
+ value 30;
+ description
+ "DS3-MIB";
+ reference
+ "RFC 3896 - Definitions of Managed Objects for the
+ DS3/E3 Interface Type";
+ }
+ enum "sip" {
+ value 31;
+ description
+ "SMDS, coffee";
+ reference
+ "RFC 1694 - Definitions of Managed Objects for SMDS
+ Interfaces using SMIv2";
+ }
+ enum "frameRelay" {
+ value 32;
+ description
+ "DTE only.";
+ reference
+ "RFC 2115 - Management Information Base for Frame Relay
+ DTEs Using SMIv2";
+ }
+ enum "rs232" {
+ value 33;
+ reference
+ "RFC 1659 - Definitions of Managed Objects for RS-232-like
+ Hardware Devices using SMIv2";
+ }
+ enum "para" {
+ value 34;
+ description
+ "parallel-port";
+ reference
+ "RFC 1660 - Definitions of Managed Objects for
+ Parallel-printer-like Hardware Devices using
+ SMIv2";
+ }
+ enum "arcnet" {
+ value 35;
+ description
+ "arcnet";
+ }
+ enum "arcnetPlus" {
+ value 36;
+ description
+ "arcnet plus";
+ }
+ enum "atm" {
+ value 37;
+ description
+ "ATM cells";
+ }
+ enum "miox25" {
+ value 38;
+ reference
+ "RFC 1461 - SNMP MIB extension for Multiprotocol
+ Interconnect over X.25";
+ }
+ enum "sonet" {
+ value 39;
+ description
+ "SONET or SDH";
+ }
+ enum "x25ple" {
+ value 40;
+ reference
+ "RFC 2127 - ISDN Management Information Base using SMIv2";
+ }
+ enum "iso88022llc" {
+ value 41;
+ }
+ enum "localTalk" {
+ value 42;
+ }
+ enum "smdsDxi" {
+ value 43;
+ }
+ enum "frameRelayService" {
+ value 44;
+ description
+ "FRNETSERV-MIB";
+ reference
+ "RFC 2954 - Definitions of Managed Objects for Frame
+ Relay Service";
+ }
+ enum "v35" {
+ value 45;
+ }
+ enum "hssi" {
+ value 46;
+ }
+ enum "hippi" {
+ value 47;
+ }
+ enum "modem" {
+ value 48;
+ description
+ "Generic modem";
+ }
+ enum "aal5" {
+ value 49;
+ description
+ "AAL5 over ATM";
+ }
+ enum "sonetPath" {
+ value 50;
+ }
+ enum "sonetVT" {
+ value 51;
+ }
+ enum "smdsIcip" {
+ value 52;
+ description
+ "SMDS InterCarrier Interface";
+ }
+ enum "propVirtual" {
+ value 53;
+ description
+ "proprietary virtual/internal";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+ enum "propMultiplexor" {
+ value 54;
+ description
+ "proprietary multiplexing";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+ enum "ieee80212" {
+ value 55;
+ description
+ "100BaseVG";
+ }
+ enum "fibreChannel" {
+ value 56;
+ description
+ "Fibre Channel";
+ }
+ enum "hippiInterface" {
+ value 57;
+ description
+ "HIPPI interfaces";
+ }
+ enum "frameRelayInterconnect" {
+ value 58;
+ status obsolete;
+ description
+ "Obsolete use either
+ frameRelay(32) or frameRelayService(44).";
+ }
+ enum "aflane8023" {
+ value 59;
+ description
+ "ATM Emulated LAN for 802.3";
+ }
+ enum "aflane8025" {
+ value 60;
+ description
+ "ATM Emulated LAN for 802.5";
+ }
+ enum "cctEmul" {
+ value 61;
+ description
+ "ATM Emulated circuit";
+ }
+ enum "fastEther" {
+ value 62;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635.
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "isdn" {
+ value 63;
+ description
+ "ISDN and X.25";
+ reference
+ "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN
+ in the Packet Mode";
+ }
+ enum "v11" {
+ value 64;
+ description
+ "CCITT V.11/X.21";
+ }
+ enum "v36" {
+ value 65;
+ description
+ "CCITT V.36";
+ }
+ enum "g703at64k" {
+ value 66;
+ description
+ "CCITT G703 at 64Kbps";
+ }
+ enum "g703at2mb" {
+ value 67;
+ status obsolete;
+ description
+ "Obsolete see DS1-MIB";
+ }
+ enum "qllc" {
+ value 68;
+ description
+ "SNA QLLC";
+ }
+ enum "fastEtherFX" {
+ value 69;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "channel" {
+ value 70;
+ description
+ "channel";
+ }
+ enum "ieee80211" {
+ value 71;
+ description
+ "radio spread spectrum";
+ }
+ enum "ibm370parChan" {
+ value 72;
+ description
+ "IBM System 360/370 OEMI Channel";
+ }
+ enum "escon" {
+ value 73;
+ description
+ "IBM Enterprise Systems Connection";
+ }
+ enum "dlsw" {
+ value 74;
+ description
+ "Data Link Switching";
+ }
+ enum "isdns" {
+ value 75;
+ description
+ "ISDN S/T interface";
+ }
+ enum "isdnu" {
+ value 76;
+ description
+ "ISDN U interface";
+ }
+ enum "lapd" {
+ value 77;
+ description
+ "Link Access Protocol D";
+ }
+ enum "ipSwitch" {
+ value 78;
+ description
+ "IP Switching Objects";
+ }
+ enum "rsrb" {
+ value 79;
+ description
+ "Remote Source Route Bridging";
+ }
+ enum "atmLogical" {
+ value 80;
+ description
+ "ATM Logical Port";
+ reference
+ "RFC 3606 - Definitions of Supplemental Managed Objects
+ for ATM Interface";
+ }
+ enum "ds0" {
+ value 81;
+ description
+ "Digital Signal Level 0";
+ reference
+ "RFC 2494 - Definitions of Managed Objects for the DS0
+ and DS0 Bundle Interface Type";
+ }
+ enum "ds0Bundle" {
+ value 82;
+ description
+ "group of ds0s on the same ds1";
+ reference
+ "RFC 2494 - Definitions of Managed Objects for the DS0
+ and DS0 Bundle Interface Type";
+ }
+ enum "bsc" {
+ value 83;
+ description
+ "Bisynchronous Protocol";
+ }
+ enum "async" {
+ value 84;
+ description
+ "Asynchronous Protocol";
+ }
+ enum "cnr" {
+ value 85;
+ description
+ "Combat Net Radio";
+ }
+ enum "iso88025Dtr" {
+ value 86;
+ description
+ "ISO 802.5r DTR";
+ }
+ enum "eplrs" {
+ value 87;
+ description
+ "Ext Pos Loc Report Sys";
+ }
+ enum "arap" {
+ value 88;
+ description
+ "Appletalk Remote Access Protocol";
+ }
+ enum "propCnls" {
+ value 89;
+ description
+ "Proprietary Connectionless Protocol";
+ }
+ enum "hostPad" {
+ value 90;
+ description
+ "CCITT-ITU X.29 PAD Protocol";
+ }
+ enum "termPad" {
+ value 91;
+ description
+ "CCITT-ITU X.3 PAD Facility";
+ }
+ enum "frameRelayMPI" {
+ value 92;
+ description
+ "Multiproto Interconnect over FR";
+ }
+ enum "x213" {
+ value 93;
+ description
+ "CCITT-ITU X213";
+ }
+ enum "adsl" {
+ value 94;
+ description
+ "Asymmetric Digital Subscriber Loop";
+ }
+ enum "radsl" {
+ value 95;
+ description
+ "Rate-Adapt. Digital Subscriber Loop";
+ }
+ enum "sdsl" {
+ value 96;
+ description
+ "Symmetric Digital Subscriber Loop";
+ }
+ enum "vdsl" {
+ value 97;
+ description
+ "Very H-Speed Digital Subscrib. Loop";
+ }
+ enum "iso88025CRFPInt" {
+ value 98;
+ description
+ "ISO 802.5 CRFP";
+ }
+ enum "myrinet" {
+ value 99;
+ description
+ "Myricom Myrinet";
+ }
+ enum "voiceEM" {
+ value 100;
+ description
+ "voice recEive and transMit";
+ }
+ enum "voiceFXO" {
+ value 101;
+ description
+ "voice Foreign Exchange Office";
+ }
+ enum "voiceFXS" {
+ value 102;
+ description
+ "voice Foreign Exchange Station";
+ }
+ enum "voiceEncap" {
+ value 103;
+ description
+ "voice encapsulation";
+ }
+ enum "voiceOverIp" {
+ value 104;
+ description
+ "voice over IP encapsulation";
+ }
+ enum "atmDxi" {
+ value 105;
+ description
+ "ATM DXI";
+ }
+ enum "atmFuni" {
+ value 106;
+ description
+ "ATM FUNI";
+ }
+ enum "atmIma" {
+ value 107;
+ description
+ "ATM IMA";
+ }
+ enum "pppMultilinkBundle" {
+ value 108;
+ description
+ "PPP Multilink Bundle";
+ }
+ enum "ipOverCdlc" {
+ value 109;
+ description
+ "IBM ipOverCdlc";
+ }
+ enum "ipOverClaw" {
+ value 110;
+ description
+ "IBM Common Link Access to Workstn";
+ }
+ enum "stackToStack" {
+ value 111;
+ description
+ "IBM stackToStack";
+ }
+ enum "virtualIpAddress" {
+ value 112;
+ description
+ "IBM VIPA";
+ }
+ enum "mpc" {
+ value 113;
+ description
+ "IBM multi-protocol channel support";
+ }
+ enum "ipOverAtm" {
+ value 114;
+ description
+ "IBM ipOverAtm";
+ reference
+ "RFC 2320 - Definitions of Managed Objects for Classical IP
+ and ARP Over ATM Using SMIv2 (IPOA-MIB)";
+ }
+ enum "iso88025Fiber" {
+ value 115;
+ description
+ "ISO 802.5j Fiber Token Ring";
+ }
+ enum "tdlc" {
+ value 116;
+ description
+ "IBM twinaxial data link control";
+ }
+ enum "gigabitEthernet" {
+ value 117;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "hdlc" {
+ value 118;
+ description
+ "HDLC";
+ }
+ enum "lapf" {
+ value 119;
+ description
+ "LAP F";
+ }
+ enum "v37" {
+ value 120;
+ description
+ "V.37";
+ }
+ enum "x25mlp" {
+ value 121;
+ description
+ "Multi-Link Protocol";
+ }
+ enum "x25huntGroup" {
+ value 122;
+ description
+ "X25 Hunt Group";
+ }
+ enum "transpHdlc" {
+ value 123;
+ description
+ "Transp HDLC";
+ }
+ enum "interleave" {
+ value 124;
+ description
+ "Interleave channel";
+ }
+ enum "fast" {
+ value 125;
+ description
+ "Fast channel";
+ }
+ enum "ip" {
+ value 126;
+ description
+ "IP (for APPN HPR in IP networks)";
+ }
+ enum "docsCableMaclayer" {
+ value 127;
+ description
+ "CATV Mac Layer";
+ }
+ enum "docsCableDownstream" {
+ value 128;
+ description
+ "CATV Downstream interface";
+ }
+ enum "docsCableUpstream" {
+ value 129;
+ description
+ "CATV Upstream interface";
+ }
+ enum "a12MppSwitch" {
+ value 130;
+ description
+ "Avalon Parallel Processor";
+ }
+ enum "tunnel" {
+ value 131;
+ description
+ "Encapsulation interface";
+ }
+ enum "coffee" {
+ value 132;
+ description
+ "coffee pot";
+ reference
+ "RFC 2325 - Coffee MIB";
+ }
+ enum "ces" {
+ value 133;
+ description
+ "Circuit Emulation Service";
+ }
+ enum "atmSubInterface" {
+ value 134;
+ description
+ "ATM Sub Interface";
+ }
+ enum "l2vlan" {
+ value 135;
+ description
+ "Layer 2 Virtual LAN using 802.1Q";
+ }
+ enum "l3ipvlan" {
+ value 136;
+ description
+ "Layer 3 Virtual LAN using IP";
+ }
+ enum "l3ipxvlan" {
+ value 137;
+ description
+ "Layer 3 Virtual LAN using IPX";
+ }
+ enum "digitalPowerline" {
+ value 138;
+ description
+ "IP over Power Lines";
+ }
+ enum "mediaMailOverIp" {
+ value 139;
+ description
+ "Multimedia Mail over IP";
+ }
+ enum "dtm" {
+ value 140;
+ description
+ "Dynamic syncronous Transfer Mode";
+ }
+ enum "dcn" {
+ value 141;
+ description
+ "Data Communications Network";
+ }
+ enum "ipForward" {
+ value 142;
+ description
+ "IP Forwarding Interface";
+ }
+ enum "msdsl" {
+ value 143;
+ description
+ "Multi-rate Symmetric DSL";
+ }
+ enum "ieee1394" {
+ value 144;
+ description
+ "IEEE1394 High Performance Serial Bus";
+ }
+ enum "if-gsn" {
+ value 145;
+ description
+ "HIPPI-6400";
+ }
+ enum "dvbRccMacLayer" {
+ value 146;
+ description
+ "DVB-RCC MAC Layer";
+ }
+ enum "dvbRccDownstream" {
+ value 147;
+ description
+ "DVB-RCC Downstream Channel";
+ }
+ enum "dvbRccUpstream" {
+ value 148;
+ description
+ "DVB-RCC Upstream Channel";
+ }
+ enum "atmVirtual" {
+ value 149;
+ description
+ "ATM Virtual Interface";
+ }
+ enum "mplsTunnel" {
+ value 150;
+ description
+ "MPLS Tunnel Virtual Interface";
+ }
+ enum "srp" {
+ value 151;
+ description
+ "Spatial Reuse Protocol";
+ }
+ enum "voiceOverAtm" {
+ value 152;
+ description
+ "Voice Over ATM";
+ }
+ enum "voiceOverFrameRelay" {
+ value 153;
+ description
+ "Voice Over Frame Relay";
+ }
+ enum "idsl" {
+ value 154;
+ description
+ "Digital Subscriber Loop over ISDN";
+ }
+ enum "compositeLink" {
+ value 155;
+ description
+ "Avici Composite Link Interface";
+ }
+ enum "ss7SigLink" {
+ value 156;
+ description
+ "SS7 Signaling Link";
+ }
+ enum "propWirelessP2P" {
+ value 157;
+ description
+ "Prop. P2P wireless interface";
+ }
+ enum "frForward" {
+ value 158;
+ description
+ "Frame Forward Interface";
+ }
+ enum "rfc1483" {
+ value 159;
+ description
+ "Multiprotocol over ATM AAL5";
+ reference
+ "RFC 1483 - Multiprotocol Encapsulation over ATM
+ Adaptation Layer 5";
+ }
+ enum "usb" {
+ value 160;
+ description
+ "USB Interface";
+ }
+ enum "ieee8023adLag" {
+ value 161;
+ description
+ "IEEE 802.3ad Link Aggregate";
+ }
+ enum "bgppolicyaccounting" {
+ value 162;
+ description
+ "BGP Policy Accounting";
+ }
+ enum "frf16MfrBundle" {
+ value 163;
+ description
+ "FRF .16 Multilink Frame Relay";
+ }
+ enum "h323Gatekeeper" {
+ value 164;
+ description
+ "H323 Gatekeeper";
+ }
+ enum "h323Proxy" {
+ value 165;
+ description
+ "H323 Voice and Video Proxy";
+ }
+ enum "mpls" {
+ value 166;
+ description
+ "MPLS";
+ }
+ enum "mfSigLink" {
+ value 167;
+ description
+ "Multi-frequency signaling link";
+ }
+ enum "hdsl2" {
+ value 168;
+ description
+ "High Bit-Rate DSL - 2nd generation";
+ }
+ enum "shdsl" {
+ value 169;
+ description
+ "Multirate HDSL2";
+ }
+ enum "ds1FDL" {
+ value 170;
+ description
+ "Facility Data Link 4Kbps on a DS1";
+ }
+ enum "pos" {
+ value 171;
+ description
+ "Packet over SONET/SDH Interface";
+ }
+ enum "dvbAsiIn" {
+ value 172;
+ description
+ "DVB-ASI Input";
+ }
+ enum "dvbAsiOut" {
+ value 173;
+ description
+ "DVB-ASI Output";
+ }
+ enum "plc" {
+ value 174;
+ description
+ "Power Line Communtications";
+ }
+ enum "nfas" {
+ value 175;
+ description
+ "Non Facility Associated Signaling";
+ }
+ enum "tr008" {
+ value 176;
+ description
+ "TR008";
+ }
+ enum "gr303RDT" {
+ value 177;
+ description
+ "Remote Digital Terminal";
+ }
+ enum "gr303IDT" {
+ value 178;
+ description
+ "Integrated Digital Terminal";
+ }
+ enum "isup" {
+ value 179;
+ description
+ "ISUP";
+ }
+ enum "propDocsWirelessMaclayer" {
+ value 180;
+ description
+ "Cisco proprietary Maclayer";
+ }
+ enum "propDocsWirelessDownstream" {
+ value 181;
+ description
+ "Cisco proprietary Downstream";
+ }
+ enum "propDocsWirelessUpstream" {
+ value 182;
+ description
+ "Cisco proprietary Upstream";
+ }
+ enum "hiperlan2" {
+ value 183;
+ description
+ "HIPERLAN Type 2 Radio Interface";
+ }
+ enum "propBWAp2Mp" {
+ value 184;
+ description
+ "PropBroadbandWirelessAccesspt2multipt use of this value
+ for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f
+ is deprecated and ieee80216WMAN(237) should be used
+ instead.";
+ }
+ enum "sonetOverheadChannel" {
+ value 185;
+ description
+ "SONET Overhead Channel";
+ }
+ enum "digitalWrapperOverheadChannel" {
+ value 186;
+ description
+ "Digital Wrapper";
+ }
+ enum "aal2" {
+ value 187;
+ description
+ "ATM adaptation layer 2";
+ }
+ enum "radioMAC" {
+ value 188;
+ description
+ "MAC layer over radio links";
+ }
+ enum "atmRadio" {
+ value 189;
+ description
+ "ATM over radio links";
+ }
+ enum "imt" {
+ value 190;
+ description
+ "Inter Machine Trunks";
+ }
+ enum "mvl" {
+ value 191;
+ description
+ "Multiple Virtual Lines DSL";
+ }
+ enum "reachDSL" {
+ value 192;
+ description
+ "Long Reach DSL";
+ }
+ enum "frDlciEndPt" {
+ value 193;
+ description
+ "Frame Relay DLCI End Point";
+ }
+ enum "atmVciEndPt" {
+ value 194;
+ description
+ "ATM VCI End Point";
+ }
+ enum "opticalChannel" {
+ value 195;
+ description
+ "Optical Channel";
+ }
+ enum "opticalTransport" {
+ value 196;
+ description
+ "Optical Transport";
+ }
+ enum "propAtm" {
+ value 197;
+ description
+ "Proprietary ATM";
+ }
+ enum "voiceOverCable" {
+ value 198;
+ description
+ "Voice Over Cable Interface";
+ }
+ enum "infiniband" {
+ value 199;
+ description
+ "Infiniband";
+ }
+ enum "teLink" {
+ value 200;
+ description
+ "TE Link";
+ }
+ enum "q2931" {
+ value 201;
+ description
+ "Q.2931";
+ }
+ enum "virtualTg" {
+ value 202;
+ description
+ "Virtual Trunk Group";
+ }
+ enum "sipTg" {
+ value 203;
+ description
+ "SIP Trunk Group";
+ }
+ enum "sipSig" {
+ value 204;
+ description
+ "SIP Signaling";
+ }
+ enum "docsCableUpstreamChannel" {
+ value 205;
+ description
+ "CATV Upstream Channel";
+ }
+ enum "econet" {
+ value 206;
+ description
+ "Acorn Econet";
+ }
+ enum "pon155" {
+ value 207;
+ description
+ "FSAN 155Mb Symetrical PON interface";
+ }
+ enum "pon622" {
+ value 208;
+ description
+ "FSAN622Mb Symetrical PON interface";
+ }
+ enum "bridge" {
+ value 209;
+ description
+ "Transparent bridge interface";
+ }
+ enum "linegroup" {
+ value 210;
+ description
+ "Interface common to multiple lines";
+ }
+ enum "voiceEMFGD" {
+ value 211;
+ description
+ "voice E&M Feature Group D";
+ }
+ enum "voiceFGDEANA" {
+ value 212;
+ description
+ "voice FGD Exchange Access North American";
+ }
+ enum "voiceDID" {
+ value 213;
+ description
+ "voice Direct Inward Dialing";
+ }
+ enum "mpegTransport" {
+ value 214;
+ description
+ "MPEG transport interface";
+ }
+ enum "sixToFour" {
+ value 215;
+ status deprecated;
+ description
+ "6to4 interface (DEPRECATED)";
+ reference
+ "RFC 4087 - IP Tunnel MIB";
+ }
+ enum "gtp" {
+ value 216;
+ description
+ "GTP (GPRS Tunneling Protocol)";
+ }
+ enum "pdnEtherLoop1" {
+ value 217;
+ description
+ "Paradyne EtherLoop 1";
+ }
+ enum "pdnEtherLoop2" {
+ value 218;
+ description
+ "Paradyne EtherLoop 2";
+ }
+ enum "opticalChannelGroup" {
+ value 219;
+ description
+ "Optical Channel Group";
+ }
+ enum "homepna" {
+ value 220;
+ description
+ "HomePNA ITU-T G.989";
+ }
+ enum "gfp" {
+ value 221;
+ description
+ "Generic Framing Procedure (GFP)";
+ }
+ enum "ciscoISLvlan" {
+ value 222;
+ description
+ "Layer 2 Virtual LAN using Cisco ISL";
+ }
+ enum "actelisMetaLOOP" {
+ value 223;
+ description
+ "Acteleis proprietary MetaLOOP High Speed Link";
+ }
+ enum "fcipLink" {
+ value 224;
+ description
+ "FCIP Link";
+ }
+ enum "rpr" {
+ value 225;
+ description
+ "Resilient Packet Ring Interface Type";
+ }
+ enum "qam" {
+ value 226;
+ description
+ "RF Qam Interface";
+ }
+ enum "lmp" {
+ value 227;
+ description
+ "Link Management Protocol";
+ reference
+ "RFC 4327 - Link Management Protocol (LMP) Management
+ Information Base (MIB)";
+ }
+ enum "cblVectaStar" {
+ value 228;
+ description
+ "Cambridge Broadband Networks Limited VectaStar";
+ }
+ enum "docsCableMCmtsDownstream" {
+ value 229;
+ description
+ "CATV Modular CMTS Downstream Interface";
+ }
+ enum "adsl2" {
+ value 230;
+ status deprecated;
+ description
+ "Asymmetric Digital Subscriber Loop Version 2
+ (DEPRECATED/OBSOLETED - please use adsl2plus(238)
+ instead)";
+ reference
+ "RFC 4706 - Definitions of Managed Objects for Asymmetric
+ Digital Subscriber Line 2 (ADSL2)";
+ }
+ enum "macSecControlledIF" {
+ value 231;
+ description
+ "MACSecControlled";
+ }
+ enum "macSecUncontrolledIF" {
+ value 232;
+ description
+ "MACSecUncontrolled";
+ }
+ enum "aviciOpticalEther" {
+ value 233;
+ description
+ "Avici Optical Ethernet Aggregate";
+ }
+ enum "atmbond" {
+ value 234;
+ description
+ "atmbond";
+ }
+ enum "voiceFGDOS" {
+ value 235;
+ description
+ "voice FGD Operator Services";
+ }
+ enum "mocaVersion1" {
+ value 236;
+ description
+ "MultiMedia over Coax Alliance (MoCA) Interface
+ as documented in information provided privately to IANA";
+ }
+ enum "ieee80216WMAN" {
+ value 237;
+ description
+ "IEEE 802.16 WMAN interface";
+ }
+ enum "adsl2plus" {
+ value 238;
+ description
+ "Asymmetric Digital Subscriber Loop Version 2,
+ Version 2 Plus and all variants";
+ }
+ enum "dvbRcsMacLayer" {
+ value 239;
+ description
+ "DVB-RCS MAC Layer";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "dvbTdm" {
+ value 240;
+ description
+ "DVB Satellite TDM";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "dvbRcsTdma" {
+ value 241;
+ description
+ "DVB-RCS TDMA";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "x86Laps" {
+ value 242;
+ description
+ "LAPS based on ITU-T X.86/Y.1323";
+ }
+ enum "wwanPP" {
+ value 243;
+ description
+ "3GPP WWAN";
+ }
+ enum "wwanPP2" {
+ value 244;
+ description
+ "3GPP2 WWAN";
+ }
+ enum "voiceEBS" {
+ value 245;
+ description
+ "voice P-phone EBS physical interface";
+ }
+ enum "ifPwType" {
+ value 246;
+ description
+ "Pseudowire interface type";
+ reference
+ "RFC 5601 - Pseudowire (PW) Management Information Base";
+ }
+ enum "ilan" {
+ value 247;
+ description
+ "Internal LAN on a bridge per IEEE 802.1ap";
+ }
+ enum "pip" {
+ value 248;
+ description
+ "Provider Instance Port on a bridge per IEEE 802.1ah PBB";
+ }
+ enum "aluELP" {
+ value 249;
+ description
+ "Alcatel-Lucent Ethernet Link Protection";
+ }
+ enum "gpon" {
+ value 250;
+ description
+ "Gigabit-capable passive optical networks (G-PON) as per
+ ITU-T G.948";
+ }
+ enum "vdsl2" {
+ value 251;
+ description
+ "Very high speed digital subscriber line Version 2
+ (as per ITU-T Recommendation G.993.2)";
+ reference
+ "RFC 5650 - Definitions of Managed Objects for Very High
+ Speed Digital Subscriber Line 2 (VDSL2)";
+ }
+ enum "capwapDot11Profile" {
+ value 252;
+ description
+ "WLAN Profile Interface";
+ reference
+ "RFC 5834 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Binding MIB for
+ IEEE 802.11";
+ }
+ enum "capwapDot11Bss" {
+ value 253;
+ description
+ "WLAN BSS Interface";
+ reference
+ "RFC 5834 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Binding MIB for
+ IEEE 802.11";
+ }
+ enum "capwapWtpVirtualRadio" {
+ value 254;
+ description
+ "WTP Virtual Radio Interface";
+ reference
+ "RFC 5833 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Base MIB";
+ }
+ enum "bits" {
+ value 255;
+ description
+ "bitsport";
+ }
+ enum "docsCableUpstreamRfPort" {
+ value 256;
+ description
+ "DOCSIS CATV Upstream RF Port";
+ }
+ enum "cableDownstreamRfPort" {
+ value 257;
+ description
+ "CATV downstream RF port";
+ }
+ enum "vmwareVirtualNic" {
+ value 258;
+ description
+ "VMware Virtual Network Interface";
+ }
+ enum "ieee802154" {
+ value 259;
+ description
+ "IEEE 802.15.4 WPAN interface";
+ reference
+ "IEEE 802.15.4-2006";
+ }
+ enum "otnOdu" {
+ value 260;
+ description
+ "OTN Optical Data Unit";
+ }
+ enum "otnOtu" {
+ value 261;
+ description
+ "OTN Optical channel Transport Unit";
+ }
+ enum "ifVfiType" {
+ value 262;
+ description
+ "VPLS Forwarding Instance Interface Type";
+ }
+ enum "g9981" {
+ value 263;
+ description
+ "G.998.1 bonded interface";
+ }
+ enum "g9982" {
+ value 264;
+ description
+ "G.998.2 bonded interface";
+ }
+ enum "g9983" {
+ value 265;
+ description
+ "G.998.3 bonded interface";
+ }
+ enum "aluEpon" {
+ value 266;
+ description
+ "Ethernet Passive Optical Networks (E-PON)";
+ }
+ enum "aluEponOnu" {
+ value 267;
+ description
+ "EPON Optical Network Unit";
+ }
+ enum "aluEponPhysicalUni" {
+ value 268;
+ description
+ "EPON physical User to Network interface";
+ }
+ enum "aluEponLogicalLink" {
+ value 269;
+ description
+ "The emulation of a point-to-point link over the EPON
+ layer";
+ }
+ enum "aluGponOnu" {
+ value 270;
+ description
+ "GPON Optical Network Unit";
+ reference
+ "ITU-T G.984.2";
+ }
+ enum "aluGponPhysicalUni" {
+ value 271;
+ description
+ "GPON physical User to Network interface";
+ reference
+ "ITU-T G.984.2";
+ }
+ enum "vmwareNicTeam" {
+ value 272;
+ description
+ "VMware NIC Team";
+ }
+ // value 273 reserved by IANA
+ }
+ description
+ "This data type is used as the syntax of the 'type'
+ leaf in the 'interface' list in the YANG module
+ ietf-interface.
+
+ The definition of this typedef with the
+ addition of newly assigned values is published
+ periodically by the IANA, in either the Assigned
+ Numbers RFC, or some derivative of it specific to
+ Internet Network Management number assignments. (The
+ latest arrangements can be obtained by contacting the
+ IANA.)
+
+ Requests for new values should be made to IANA via
+ email (iana&iana.org).";
+ reference
+ "IANA ifType definitions registry.
+ <http://www.iana.org/assignments/smi-numbers>";
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-inet-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-inet-types.yang
new file mode 100644
index 0000000..de20feb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-inet-types.yang
@@ -0,0 +1,418 @@
+ module ietf-inet-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+ prefix "inet";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ typedef ip-version {
+ type enumeration {
+ enum unknown {
+ value "0";
+ description
+ "An unknown or unspecified version of the Internet protocol.";
+ }
+ enum ipv4 {
+ value "1";
+ description
+ "The IPv4 protocol as defined in RFC 791.";
+ }
+ enum ipv6 {
+ value "2";
+ description
+ "The IPv6 protocol as defined in RFC 2460.";
+ }
+ }
+ description
+ "This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.";
+ reference
+ "RFC 791: Internet Protocol
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ typedef dscp {
+ type uint8 {
+ range "0..63";
+ }
+ description
+ "The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.";
+ reference
+ "RFC 3289: Management Information Base for the Differentiated
+ Services Architecture
+ RFC 2474: Definition of the Differentiated Services Field
+ (DS Field) in the IPv4 and IPv6 Headers
+ RFC 2780: IANA Allocation Guidelines For Values In
+ the Internet Protocol and Related Headers";
+ }
+
+ typedef ipv6-flow-label {
+ type uint32 {
+ range "0..1048575";
+ }
+ description
+ "The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.";
+ reference
+ "RFC 3595: Textual Conventions for IPv6 Flow Label
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+ }
+
+ typedef port-number {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.";
+ reference
+ "RFC 768: User Datagram Protocol
+ RFC 793: Transmission Control Protocol
+ RFC 4960: Stream Control Transmission Protocol
+ RFC 4340: Datagram Congestion Control Protocol (DCCP)
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of autonomous system related types ***/
+
+ typedef as-number {
+ type uint32;
+ description
+ "The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.";
+ reference
+ "RFC 1930: Guidelines for creation, selection, and registration
+ of an Autonomous System (AS)
+ RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+ RFC 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ typedef ip-address {
+ type union {
+ type inet:ipv4-address;
+ type inet:ipv6-address;
+ }
+ description
+ "The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '(%[\p{N}\p{L}]+)?';
+ }
+ description
+ "The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format";
+ }
+
+ typedef ipv6-address {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(%[\p{N}\p{L}]+)?';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(%.+)?';
+ }
+ description
+ "The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture
+ RFC 4007: IPv6 Scoped Address Architecture
+ RFC 5952: A Recommendation for IPv6 Address Text Representation";
+ }
+
+ typedef ip-prefix {
+ type union {
+ type inet:ipv4-prefix;
+ type inet:ipv6-prefix;
+ }
+ description
+ "The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-prefix {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+ }
+ description
+ "The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.";
+ }
+
+ typedef ipv6-prefix {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(/.+)';
+ }
+ description
+ "The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** collection of domain name and URI types ***/
+
+ typedef domain-name {
+ type string {
+ pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ + '|\.';
+ length "1..253";
+ }
+ description
+ "The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492";
+ reference
+ "RFC 952: DoD Internet Host Table Specification
+ RFC 1034: Domain Names - Concepts and Facilities
+ RFC 1123: Requirements for Internet Hosts -- Application
+ and Support
+ RFC 2782: A DNS RR for specifying the location of services
+ (DNS SRV)
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ typedef host {
+ type union {
+ type inet:ip-address;
+ type inet:domain-name;
+ }
+ description
+ "The host type represents either an IP address or a DNS
+ domain name.";
+ }
+
+ typedef uri {
+ type string;
+ description
+ "The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.";
+ reference
+ "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+ Group: Uniform Resource Identifiers (URIs), URLs,
+ and Uniform Resource Names (URNs): Clarifications
+ and Recommendations
+ RFC 5017: MIB Textual Conventions for Uniform Resource
+ Identifiers (URIs)";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-interfaces@2013-07-04.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-interfaces@2013-07-04.yang
new file mode 100644
index 0000000..9db753c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-interfaces@2013-07-04.yang
@@ -0,0 +1,673 @@
+module ietf-interfaces {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+ prefix if;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import iana-if-type {
+ prefix ianaift;
+ }
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ WG Chair: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>";
+
+ description
+ "This module contains a collection of YANG definitions for
+ managing network interfaces.
+
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-07-04 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: A YANG Data Model for Interface Management";
+ }
+
+ /* Typedefs */
+
+ typedef interface-ref {
+ type leafref {
+ path "/if:interfaces/if:interface/if:name";
+ }
+ description
+ "This type is used by data models that need to reference
+ configured interfaces.";
+ }
+
+ typedef interface-state-ref {
+ type leafref {
+ path "/if:interfaces-state/if:interface/if:name";
+ }
+ description
+ "This type is used by data models that need to reference
+ the operationally present interfaces.";
+ }
+
+ /* Features */
+
+ feature arbitrary-names {
+ description
+ "This feature indicates that the device allows user-controlled
+ interfaces to be named arbitrarily.";
+ }
+
+ feature pre-provisioning {
+ description
+ "This feature indicates that the device supports
+ pre-provisioning of interface configuration, i.e., it is
+ possible to configure an interface whose physical interface
+ hardware is not present on the device.";
+ }
+
+ feature if-mib {
+ description
+ "This feature indicates that the device implements IF-MIB.";
+ reference
+ "RFC 2863: The Interfaces Group MIB";
+ }
+
+ /* Data nodes */
+
+ container interfaces {
+ description
+ "Interface configuration parameters.";
+
+ list interface {
+ key "name";
+
+ description
+ "The list of configured interfaces on the device.
+
+ The operational state of an interface is available in the
+ /interfaces-state/interface list. If the configuration of a
+ system-controlled interface cannot be used by the system
+ (e.g., the interface hardware present does not match the
+ interface type), then the configuration is not applied to
+ the system-controlled interface shown in the
+ /interfaces-state/interface list. If the the configuration
+ of a user-controlled interface cannot be used by the system,
+ the configured interface is not instantiated in the
+ /interfaces-state/interface list.";
+
+ leaf name {
+ type string;
+ description
+ "The name of the interface.
+
+ A device MAY restrict the allowed values for this leaf,
+ possibly depending on the type of the interface.
+
+ For system-controlled interfaces, this leaf is the
+ device-specific name of the interface. The 'config false'
+ list /interfaces-state/interface contains the currently
+ existing interfaces on the device.
+
+ If a client tries to create configuration for a
+ system-controlled interface that is not present in the
+ /interfaces-state/interface list, the server MAY reject
+ the request, if the implementation does not support
+ pre-provisioning of interfaces, or if the name refers to
+ an interface that can never exist in the system. A
+ NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.
+
+ If the device supports pre-provisioning of interface
+ configuration, the feature 'pre-provisioning' is
+ advertised.
+
+ If the device allows arbitrarily named user-controlled
+ interfaces, the feature 'arbitrary-names' is advertised.
+
+ When a configured user-controlled interface is created by
+ the system, it is instantiated with the same name in the
+ /interface-state/interface list. Since the name in that
+ list MAY be mapped to ifName by an implementation, such an
+ implementation MUST restrict the allowed values for this
+ leaf so that it matches the restrictions of ifName.
+
+ If a NETCONF server that implements this restriction is
+ sent a value that doesn't match the restriction, it MUST
+ reply with an rpc-error with the error-tag
+ 'invalid-value'.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "A textual description of the interface.
+
+ This leaf MAY be mapped to ifAlias by an implementation.
+ Such an implementation MUST restrict the allowed values
+ for this leaf so that it matches the restrictions of
+ ifAlias.
+
+ If a NETCONF server that implements this restriction is
+ sent a value that doesn't match the restriction, it MUST
+ reply with an rpc-error with the error-tag
+ 'invalid-value'.
+
+ Since ifAlias is defined to be stored in non-volatile
+ storage, the MIB implementation MUST map ifAlias to the
+ value of 'description' in the persistently stored
+ datastore.
+
+ Specifically, if the device supports ':startup', when
+ ifAlias is read the device MUST return the value of
+ 'description' in the 'startup' datastore, and when it is
+ written, it MUST be written to the 'running' and 'startup'
+ datastores. Note that it is up to the implementation if
+ it modifies this single leaf in 'startup', or if it
+ performs an implicit copy-config from 'running' to
+ 'startup'.
+
+ If the device does not support ':startup', ifAlias MUST
+ be mapped to the 'description' leaf in the 'running'
+ datastore.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAlias";
+ }
+
+ leaf type {
+ type ianaift:iana-if-type;
+ mandatory true;
+ description
+ "The type of the interface.
+
+ When an interface entry is created, a server MAY
+ initialize the type leaf with a valid value, e.g., if it
+ is possible to derive the type from the name of the
+ interface.
+
+ If a client tries to set the type of an interface to a
+ value that can never be used by the system, e.g., if the
+ type is not supported or if the type does not match the
+ name of the interface, the server MUST reject the request.
+ A NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf enabled {
+ type boolean;
+ default "true";
+ description
+ "This leaf contains the configured, desired state of the
+ interface.
+
+ Systems that implement the IF-MIB use the value of this
+ leaf in the 'running' datastore to set
+ IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
+ has been initialized, as described in RFC 2863.
+
+ Changes in this leaf in the 'running' datastore are
+ reflected in ifAdminStatus, but if ifAdminStatus is
+ changed over SNMP, this leaf is not affected.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf link-up-down-trap-enable {
+ if-feature if-mib;
+ type enumeration {
+ enum enabled {
+ value 1;
+ }
+ enum disabled {
+ value 2;
+ }
+ }
+ description
+ "Controls whether linkUp/linkDown SNMP notifications
+ should be generated for this interface.
+
+ If this node is not configured, the value 'enabled' is
+ operationally used by the server for interfaces which do
+ not operate on top of any other interface (i.e., there are
+ no 'lower-layer-if' entries), and 'disabled' otherwise.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifLinkUpDownTrapEnable";
+ }
+ }
+ }
+
+ container interfaces-state {
+ config false;
+ description
+ "Data nodes for the operational state of interfaces.";
+
+ list interface {
+ key "name";
+
+ description
+ "The list of interfaces on the device.
+
+ System-controlled interfaces created by the system are
+ always present in this list, whether they are configured or
+ not.";
+
+ leaf name {
+ type string;
+ description
+ "The name of the interface.
+
+ This leaf MAY be mapped to ifName by an implementation.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifName";
+ }
+
+ leaf type {
+ type ianaift:iana-if-type;
+ mandatory true;
+ description
+ "The type of the interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf admin-status {
+ if-feature if-mib;
+ type enumeration {
+ enum up {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum down {
+ value 2;
+ description
+ "Not ready to pass packets and not in some test mode.";
+ }
+ enum testing {
+ value 3;
+ description
+ "In some test mode.";
+ }
+ }
+ mandatory true;
+ description
+ "The desired state of the interface.
+
+ This leaf has the same read semantics as ifAdminStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf oper-status {
+ type enumeration {
+ enum up {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum down {
+ value 2;
+ description
+ "The interface does not pass any packets.";
+ }
+ enum testing {
+ value 3;
+ description
+ "In some test mode. No operational packets can
+ be passed.";
+ }
+ enum unknown {
+ value 4;
+ description
+ "Status cannot be determined for some reason.";
+ }
+ enum dormant {
+ value 5;
+ description
+ "Waiting for some external event.";
+ }
+ enum not-present {
+ value 6;
+ description
+ "Some component (typically hardware) is missing.";
+ }
+ enum lower-layer-down {
+ value 7;
+ description
+ "Down due to state of lower-layer interface(s).";
+ }
+ }
+ mandatory true;
+ description
+ "The current operational state of the interface.
+
+ This leaf has the same semantics as ifOperStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOperStatus";
+ }
+
+ leaf last-change {
+ type yang:date-and-time;
+ description
+ "The time the interface entered its current operational
+ state. If the current state was entered prior to the
+ last re-initialization of the local network management
+ subsystem, then this node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifLastChange";
+ }
+
+ leaf if-index {
+ if-feature if-mib;
+ type int32 {
+ range "1..2147483647";
+ }
+ mandatory true;
+ description
+ "The ifIndex value for the ifEntry represented by this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifIndex";
+ }
+
+ leaf phys-address {
+ type yang:phys-address;
+ description
+ "The interface's address at its protocol sub-layer. For
+ example, for an 802.x interface, this object normally
+ contains a MAC address. The interface's media-specific
+ modules must define the bit and byte ordering and the
+ format of the value of this object. For interfaces that do
+ not have such an address (e.g., a serial line), this node
+ is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifPhysAddress";
+ }
+
+ leaf-list higher-layer-if {
+ type interface-state-ref;
+ description
+ "A list of references to interfaces layered on top of this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifStackTable";
+ }
+
+ leaf-list lower-layer-if {
+ type interface-state-ref;
+ description
+ "A list of references to interfaces layered underneath this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifStackTable";
+ }
+
+ leaf speed {
+ type yang:gauge64;
+ units "bits / second";
+ description
+ "An estimate of the interface's current bandwidth in bits
+ per second. For interfaces that do not vary in
+ bandwidth or for those where no accurate estimation can
+ be made, this node should contain the nominal bandwidth.
+ For interfaces that have no concept of bandwidth, this
+ node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifSpeed, ifHighSpeed";
+ }
+
+ container statistics {
+ description
+ "A collection of interface-related statistics objects.";
+
+ leaf discontinuity-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time on the most recent occasion at which any one or
+ more of this interface's counters suffered a
+ discontinuity. If no such discontinuities have occurred
+ since the last re-initialization of the local management
+ subsystem, then this node contains the time the local
+ management subsystem re-initialized itself.";
+ }
+
+ leaf in-octets {
+ type yang:counter64;
+ description
+ "The total number of octets received on the interface,
+ including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInOctets";
+ }
+ leaf in-unicast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were not addressed to a
+ multicast or broadcast address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
+ }
+ leaf in-broadcast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were addressed to a broadcast
+ address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInBroadcastPkts";
+ }
+ leaf in-multicast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were addressed to a multicast
+ address at this sub-layer. For a MAC layer protocol,
+ this includes both Group and Functional addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInMulticastPkts";
+ }
+ leaf in-discards {
+ type yang:counter32;
+ description
+ "The number of inbound packets which were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being deliverable to a higher-layer
+ protocol. One possible reason for discarding such a
+ packet could be to free up buffer space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInDiscards";
+ }
+ leaf in-errors {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of inbound
+ packets that contained errors preventing them from being
+ deliverable to a higher-layer protocol. For character-
+ oriented or fixed-length interfaces, the number of
+ inbound transmission units that contained errors
+ preventing them from being deliverable to a higher-layer
+ protocol.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInErrors";
+ }
+ leaf in-unknown-protos {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of packets
+ received via the interface which were discarded because
+ of an unknown or unsupported protocol. For
+ character-oriented or fixed-length interfaces that
+ support protocol multiplexing the number of transmission
+ units received via the interface which were discarded
+ because of an unknown or unsupported protocol. For any
+ interface that does not support protocol multiplexing,
+ this counter is not present.
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
+ }
+
+ leaf out-octets {
+ type yang:counter64;
+ description
+ "The total number of octets transmitted out of the
+ interface, including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
+ }
+ leaf out-unicast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were not addressed
+ to a multicast or broadcast address at this sub-layer,
+ including those that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
+ }
+ leaf out-broadcast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were addressed to a
+ broadcast address at this sub-layer, including those
+ that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutBroadcastPkts";
+ }
+ leaf out-multicast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were addressed to a
+ multicast address at this sub-layer, including those
+ that were discarded or not sent. For a MAC layer
+ protocol, this includes both Group and Functional
+ addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutMulticastPkts";
+ }
+ leaf out-discards {
+ type yang:counter32;
+ description
+ "The number of outbound packets which were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being transmitted. One possible reason
+ for discarding such a packet could be to free up buffer
+ space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutDiscards";
+ }
+ leaf out-errors {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of outbound
+ packets that could not be transmitted because of errors.
+ For character-oriented or fixed-length interfaces, the
+ number of outbound transmission units that could not be
+ transmitted because of errors.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutErrors";
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-restconf-monitoring@2017-01-26.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-restconf-monitoring@2017-01-26.yang
new file mode 100644
index 0000000..55c3cb1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-restconf-monitoring@2017-01-26.yang
@@ -0,0 +1,149 @@
+module ietf-restconf-monitoring {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring";
+ prefix "rcmon";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ Author: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Author: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Author: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+
+ description
+ "This module contains monitoring information for the
+ RESTCONF protocol.
+
+ Copyright (c) 2017 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 8040; see
+ the RFC itself for full legal notices.";
+
+ revision 2017-01-26 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 8040: RESTCONF Protocol.";
+ }
+
+ container restconf-state {
+ config false;
+ description
+ "Contains RESTCONF protocol monitoring information.";
+
+ container capabilities {
+ description
+ "Contains a list of protocol capability URIs.";
+
+ leaf-list capability {
+ type inet:uri;
+ description
+ "A RESTCONF protocol capability URI.";
+ }
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description
+ "The stream name.";
+ reference
+ "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "Description of stream content.";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ default false;
+ description
+ "Indicates if replay buffer is supported for this stream.
+ If 'true', then the server MUST support the 'start-time'
+ and 'stop-time' query parameters for this stream.";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ when "../replay-support" {
+ description
+ "Only present if notification replay is supported.";
+ }
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ list access {
+ key encoding;
+ min-elements 1;
+ description
+ "The server will create an entry in this list for each
+ encoding format that is supported for this stream.
+ The media type 'text/event-stream' is expected
+ for all event streams. This list identifies the
+ subtypes supported for this stream.";
+
+ leaf encoding {
+ type string;
+ description
+ "This is the secondary encoding format within the
+ 'text/event-stream' encoding used by all streams.
+ The type 'xml' is supported for XML encoding.
+ The type 'json' is supported for JSON encoding.";
+ }
+
+ leaf location {
+ type inet:uri;
+ mandatory true;
+ description
+ "Contains a URL that represents the entry point
+ for establishing notification delivery via
+ server-sent events.";
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-restconf@2013-10-19.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-restconf@2013-10-19.yang
new file mode 100644
index 0000000..16766b0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-restconf@2013-10-19.yang
@@ -0,0 +1,684 @@
+module ietf-restconf {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ container modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one module currently
+ supported by the server.";
+
+ leaf name {
+ type yang:yang-identifier;
+ description "The YANG module name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module revision date. An empty string is
+ used if no revision statement is present in the
+ YANG module.";
+ }
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server.";
+ }
+ leaf-list deviation {
+ type yang:yang-identifier;
+ description
+ "List of YANG deviation module names used by this
+ server to modify the conformance of the module
+ associated with this entry.";
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ } \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-yang-library@2016-06-21.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-yang-library@2016-06-21.yang
new file mode 100644
index 0000000..bc466ee
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-yang-library@2016-06-21.yang
@@ -0,0 +1,208 @@
+module ietf-yang-library {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-library";
+ prefix "yanglib";
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import ietf-inet-types {
+ prefix inet;
+ }
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+ WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+ WG Chair: Mahesh Jethanandani
+ <mailto:mjethanandani@gmail.com>
+ Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+ description
+ "This module contains monitoring information about the YANG
+ modules and submodules that are used within a YANG-based
+ server.
+ Copyright (c) 2016 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+ This version of this YANG module is part of RFC 7895; see
+ the RFC itself for full legal notices.";
+ revision 2016-06-21 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 7895: YANG Module Library.";
+ }
+ /*
+ * Typedefs
+ */
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.";
+ }
+ /*
+ * Groupings
+ */
+ grouping module-list {
+ description
+ "The module data structure is represented as a grouping
+ so it can be reused in configuration or another monitoring
+ data structure.";
+ grouping common-leafs {
+ description
+ "Common parameters for YANG modules and submodules.";
+ leaf name {
+ type yang:yang-identifier;
+ description
+ "The YANG module or submodule name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module or submodule revision date.
+ A zero-length string is used if no revision statement
+ is present in the YANG module or submodule.";
+ }
+ }
+ grouping schema-leaf {
+ description
+ "Common schema leaf parameter for modules and submodules.";
+ leaf schema {
+ type inet:uri;
+ description
+ "Contains a URL that represents the YANG schema
+ resource for this module or submodule.
+ This leaf will only be present if there is a URL
+ available for retrieval of the schema for this entry.";
+ }
+ }
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one revision of one module
+ currently supported by the server.";
+ uses common-leafs;
+ uses schema-leaf;
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server, regardless of whether they are
+ defined in the module or any included submodule.";
+ }
+ list deviation {
+ key "name revision";
+ description
+ "List of YANG deviation module names and revisions
+ used by this server to modify the conformance of
+ the module associated with this entry. Note that
+ the same module can be used for deviations for
+ multiple modules, so the same entry MAY appear
+ within multiple 'module' entries.
+ The deviation module MUST be present in the 'module'
+ list, with the same name and revision values.
+ The 'conformance-type' value will be 'implement' for
+ the deviation module.";
+ uses common-leafs;
+ }
+ leaf conformance-type {
+ type enumeration {
+ enum implement {
+ description
+ "Indicates that the server implements one or more
+ protocol-accessible objects defined in the YANG module
+ identified in this entry. This includes deviation
+ statements defined in the module.
+ For YANG version 1.1 modules, there is at most one
+ module entry with conformance type 'implement' for a
+ particular module name, since YANG 1.1 requires that,
+ at most, one revision of a module is implemented.
+ For YANG version 1 modules, there SHOULD NOT be more
+ than one module entry for a particular module name.";
+ }
+ enum import {
+ description
+ "Indicates that the server imports reusable definitions
+ from the specified revision of the module but does
+ not implement any protocol-accessible objects from
+ this revision.
+ Multiple module entries for the same module name MAY
+ exist. This can occur if multiple modules import the
+ same module but specify different revision dates in
+ the import statements.";
+ }
+ }
+ mandatory true;
+ description
+ "Indicates the type of conformance the server is claiming
+ for the YANG module identified by this entry.";
+ }
+ list submodule {
+ key "name revision";
+ description
+ "Each entry represents one submodule within the
+ parent module.";
+ uses common-leafs;
+ uses schema-leaf;
+ }
+ }
+ }
+ /*
+ * Operational state data nodes
+ */
+ container modules-state {
+ config false;
+ description
+ "Contains YANG module monitoring information.";
+ leaf module-set-id {
+ type string;
+ mandatory true;
+ description
+ "Contains a server-specific identifier representing
+ the current set of modules and submodules. The
+ server MUST change the value of this leaf if the
+ information represented by the 'module' list instances
+ has changed.";
+ }
+ uses module-list;
+ }
+ /*
+ * Notifications
+ */
+ notification yang-library-change {
+ description
+ "Generated when the set of modules and submodules supported
+ by the server has changed.";
+ leaf module-set-id {
+ type leafref {
+ path "/yanglib:modules-state/yanglib:module-set-id";
+ }
+ mandatory true;
+ description
+ "Contains the module-set-id value representing the
+ set of modules and submodules supported at the server at
+ the time the notification is generated.";
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-yang-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-yang-types.yang
new file mode 100644
index 0000000..c3f952c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/ietf-yang-types.yang
@@ -0,0 +1,417 @@
+ module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+
+
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined by the 'identifier'
+ rule in Section 12 of RFC 6020. An identifier must
+ start with an alphabetic character or an underscore
+ followed by an arbitrary sequence of alphabetic or
+ numeric characters, underscores, hyphens, or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lowercase or uppercase character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using the
+ time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually referring
+ to the notion of local time) uses the time-offset -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence happened.
+ The specific occurrence must be defined in the description
+ of any schema node defined using this type. When the specific
+ occurrence occurred prior to the last time the associated
+ timeticks attribute was zero, then the timestamp value is
+ zero. Note that this requires all timestamp values to be
+ reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module1.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module1.yang
new file mode 100644
index 0000000..604fe94
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module1.yang
@@ -0,0 +1,12 @@
+module module1 {
+ namespace "module:1";
+ prefix "mod1";
+ revision "2014-01-01";
+
+ rpc dummy-rpc1-module1 {
+ }
+
+ rpc dummy-rpc2-module1 {
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module2.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module2.yang
new file mode 100644
index 0000000..7b359f3
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module2.yang
@@ -0,0 +1,11 @@
+module module2 {
+ namespace "module:2";
+ prefix "mod2";
+ revision "2014-01-02";
+
+ rpc dummy-rpc1-module2 {
+ }
+
+ rpc dummy-rpc2-module2 {
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module3.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module3.yang
new file mode 100644
index 0000000..39bb690
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/module3.yang
@@ -0,0 +1,5 @@
+module module3 {
+ namespace "module:3";
+ prefix "mod3";
+ revision "2014-01-03";
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/iana-if-type.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/iana-if-type.yang
new file mode 100644
index 0000000..7bd0003
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/iana-if-type.yang
@@ -0,0 +1,1517 @@
+module iana-if-type {
+ namespace "urn:ietf:params:xml:ns:yang:iana-if-type";
+ prefix ianaift;
+
+ organization "IANA";
+ contact
+ " Internet Assigned Numbers Authority
+
+ Postal: ICANN
+ 4676 Admiralty Way, Suite 330
+ Marina del Rey, CA 90292
+
+ Tel: +1 310 823 9358
+ E-Mail: iana&iana.org";
+ description
+ "This YANG module defines the iana-if-type typedef, which
+ contains YANG definitions for IANA-registered interface types.
+
+ This YANG module is maintained by IANA, and reflects the
+ 'ifType definitions' registry.
+
+ The latest revision of this YANG module can be obtained from
+ the IANA web site.
+
+ Copyright (c) 2011 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-07-04 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: IANA Interface Type YANG Module";
+ }
+
+ typedef iana-if-type {
+ type enumeration {
+ enum "other" {
+ value 1;
+ description
+ "None of the following";
+ }
+ enum "regular1822" {
+ value 2;
+ }
+ enum "hdh1822" {
+ value 3;
+ }
+ enum "ddnX25" {
+ value 4;
+ }
+ enum "rfc877x25" {
+ value 5;
+ reference
+ "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer";
+ }
+ enum "ethernetCsmacd" {
+ value 6;
+ description
+ "For all ethernet-like interfaces, regardless of speed,
+ as per RFC3635.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "iso88023Csmacd" {
+ value 7;
+ status deprecated;
+ description
+ "Deprecated via RFC3635.
+ Use ethernetCsmacd(6) instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "iso88024TokenBus" {
+ value 8;
+ }
+ enum "iso88025TokenRing" {
+ value 9;
+ }
+ enum "iso88026Man" {
+ value 10;
+ }
+ enum "starLan" {
+ value 11;
+ status deprecated;
+ description
+ "Deprecated via RFC3635.
+ Use ethernetCsmacd(6) instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "proteon10Mbit" {
+ value 12;
+ }
+ enum "proteon80Mbit" {
+ value 13;
+ }
+ enum "hyperchannel" {
+ value 14;
+ }
+ enum "fddi" {
+ value 15;
+ reference
+ "RFC 1512 - FDDI Management Information Base";
+ }
+ enum "lapb" {
+ value 16;
+ reference
+ "RFC 1381 - SNMP MIB Extension for X.25 LAPB";
+ }
+ enum "sdlc" {
+ value 17;
+ }
+ enum "ds1" {
+ value 18;
+ description
+ "DS1-MIB";
+ reference
+ "RFC 4805 - Definitions of Managed Objects for the
+ DS1, J1, E1, DS2, and E2 Interface Types";
+ }
+ enum "e1" {
+ value 19;
+ status obsolete;
+ description
+ "Obsolete see DS1-MIB";
+ reference
+ "RFC 4805 - Definitions of Managed Objects for the
+ DS1, J1, E1, DS2, and E2 Interface Types";
+ }
+ enum "basicISDN" {
+ value 20;
+ description
+ "see also RFC2127";
+ }
+ enum "primaryISDN" {
+ value 21;
+ }
+ enum "propPointToPointSerial" {
+ value 22;
+ description
+ "proprietary serial";
+ }
+ enum "ppp" {
+ value 23;
+ }
+ enum "softwareLoopback" {
+ value 24;
+ }
+ enum "eon" {
+ value 25;
+ description
+ "CLNP over IP";
+ }
+ enum "ethernet3Mbit" {
+ value 26;
+ }
+ enum "nsip" {
+ value 27;
+ description
+ "XNS over IP";
+ }
+ enum "slip" {
+ value 28;
+ description
+ "generic SLIP";
+ }
+ enum "ultra" {
+ value 29;
+ description
+ "ULTRA technologies";
+ }
+ enum "ds3" {
+ value 30;
+ description
+ "DS3-MIB";
+ reference
+ "RFC 3896 - Definitions of Managed Objects for the
+ DS3/E3 Interface Type";
+ }
+ enum "sip" {
+ value 31;
+ description
+ "SMDS, coffee";
+ reference
+ "RFC 1694 - Definitions of Managed Objects for SMDS
+ Interfaces using SMIv2";
+ }
+ enum "frameRelay" {
+ value 32;
+ description
+ "DTE only.";
+ reference
+ "RFC 2115 - Management Information Base for Frame Relay
+ DTEs Using SMIv2";
+ }
+ enum "rs232" {
+ value 33;
+ reference
+ "RFC 1659 - Definitions of Managed Objects for RS-232-like
+ Hardware Devices using SMIv2";
+ }
+ enum "para" {
+ value 34;
+ description
+ "parallel-port";
+ reference
+ "RFC 1660 - Definitions of Managed Objects for
+ Parallel-printer-like Hardware Devices using
+ SMIv2";
+ }
+ enum "arcnet" {
+ value 35;
+ description
+ "arcnet";
+ }
+ enum "arcnetPlus" {
+ value 36;
+ description
+ "arcnet plus";
+ }
+ enum "atm" {
+ value 37;
+ description
+ "ATM cells";
+ }
+ enum "miox25" {
+ value 38;
+ reference
+ "RFC 1461 - SNMP MIB extension for Multiprotocol
+ Interconnect over X.25";
+ }
+ enum "sonet" {
+ value 39;
+ description
+ "SONET or SDH";
+ }
+ enum "x25ple" {
+ value 40;
+ reference
+ "RFC 2127 - ISDN Management Information Base using SMIv2";
+ }
+ enum "iso88022llc" {
+ value 41;
+ }
+ enum "localTalk" {
+ value 42;
+ }
+ enum "smdsDxi" {
+ value 43;
+ }
+ enum "frameRelayService" {
+ value 44;
+ description
+ "FRNETSERV-MIB";
+ reference
+ "RFC 2954 - Definitions of Managed Objects for Frame
+ Relay Service";
+ }
+ enum "v35" {
+ value 45;
+ }
+ enum "hssi" {
+ value 46;
+ }
+ enum "hippi" {
+ value 47;
+ }
+ enum "modem" {
+ value 48;
+ description
+ "Generic modem";
+ }
+ enum "aal5" {
+ value 49;
+ description
+ "AAL5 over ATM";
+ }
+ enum "sonetPath" {
+ value 50;
+ }
+ enum "sonetVT" {
+ value 51;
+ }
+ enum "smdsIcip" {
+ value 52;
+ description
+ "SMDS InterCarrier Interface";
+ }
+ enum "propVirtual" {
+ value 53;
+ description
+ "proprietary virtual/internal";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+ enum "propMultiplexor" {
+ value 54;
+ description
+ "proprietary multiplexing";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+ enum "ieee80212" {
+ value 55;
+ description
+ "100BaseVG";
+ }
+ enum "fibreChannel" {
+ value 56;
+ description
+ "Fibre Channel";
+ }
+ enum "hippiInterface" {
+ value 57;
+ description
+ "HIPPI interfaces";
+ }
+ enum "frameRelayInterconnect" {
+ value 58;
+ status obsolete;
+ description
+ "Obsolete use either
+ frameRelay(32) or frameRelayService(44).";
+ }
+ enum "aflane8023" {
+ value 59;
+ description
+ "ATM Emulated LAN for 802.3";
+ }
+ enum "aflane8025" {
+ value 60;
+ description
+ "ATM Emulated LAN for 802.5";
+ }
+ enum "cctEmul" {
+ value 61;
+ description
+ "ATM Emulated circuit";
+ }
+ enum "fastEther" {
+ value 62;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635.
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "isdn" {
+ value 63;
+ description
+ "ISDN and X.25";
+ reference
+ "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN
+ in the Packet Mode";
+ }
+ enum "v11" {
+ value 64;
+ description
+ "CCITT V.11/X.21";
+ }
+ enum "v36" {
+ value 65;
+ description
+ "CCITT V.36";
+ }
+ enum "g703at64k" {
+ value 66;
+ description
+ "CCITT G703 at 64Kbps";
+ }
+ enum "g703at2mb" {
+ value 67;
+ status obsolete;
+ description
+ "Obsolete see DS1-MIB";
+ }
+ enum "qllc" {
+ value 68;
+ description
+ "SNA QLLC";
+ }
+ enum "fastEtherFX" {
+ value 69;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "channel" {
+ value 70;
+ description
+ "channel";
+ }
+ enum "ieee80211" {
+ value 71;
+ description
+ "radio spread spectrum";
+ }
+ enum "ibm370parChan" {
+ value 72;
+ description
+ "IBM System 360/370 OEMI Channel";
+ }
+ enum "escon" {
+ value 73;
+ description
+ "IBM Enterprise Systems Connection";
+ }
+ enum "dlsw" {
+ value 74;
+ description
+ "Data Link Switching";
+ }
+ enum "isdns" {
+ value 75;
+ description
+ "ISDN S/T interface";
+ }
+ enum "isdnu" {
+ value 76;
+ description
+ "ISDN U interface";
+ }
+ enum "lapd" {
+ value 77;
+ description
+ "Link Access Protocol D";
+ }
+ enum "ipSwitch" {
+ value 78;
+ description
+ "IP Switching Objects";
+ }
+ enum "rsrb" {
+ value 79;
+ description
+ "Remote Source Route Bridging";
+ }
+ enum "atmLogical" {
+ value 80;
+ description
+ "ATM Logical Port";
+ reference
+ "RFC 3606 - Definitions of Supplemental Managed Objects
+ for ATM Interface";
+ }
+ enum "ds0" {
+ value 81;
+ description
+ "Digital Signal Level 0";
+ reference
+ "RFC 2494 - Definitions of Managed Objects for the DS0
+ and DS0 Bundle Interface Type";
+ }
+ enum "ds0Bundle" {
+ value 82;
+ description
+ "group of ds0s on the same ds1";
+ reference
+ "RFC 2494 - Definitions of Managed Objects for the DS0
+ and DS0 Bundle Interface Type";
+ }
+ enum "bsc" {
+ value 83;
+ description
+ "Bisynchronous Protocol";
+ }
+ enum "async" {
+ value 84;
+ description
+ "Asynchronous Protocol";
+ }
+ enum "cnr" {
+ value 85;
+ description
+ "Combat Net Radio";
+ }
+ enum "iso88025Dtr" {
+ value 86;
+ description
+ "ISO 802.5r DTR";
+ }
+ enum "eplrs" {
+ value 87;
+ description
+ "Ext Pos Loc Report Sys";
+ }
+ enum "arap" {
+ value 88;
+ description
+ "Appletalk Remote Access Protocol";
+ }
+ enum "propCnls" {
+ value 89;
+ description
+ "Proprietary Connectionless Protocol";
+ }
+ enum "hostPad" {
+ value 90;
+ description
+ "CCITT-ITU X.29 PAD Protocol";
+ }
+ enum "termPad" {
+ value 91;
+ description
+ "CCITT-ITU X.3 PAD Facility";
+ }
+ enum "frameRelayMPI" {
+ value 92;
+ description
+ "Multiproto Interconnect over FR";
+ }
+ enum "x213" {
+ value 93;
+ description
+ "CCITT-ITU X213";
+ }
+ enum "adsl" {
+ value 94;
+ description
+ "Asymmetric Digital Subscriber Loop";
+ }
+ enum "radsl" {
+ value 95;
+ description
+ "Rate-Adapt. Digital Subscriber Loop";
+ }
+ enum "sdsl" {
+ value 96;
+ description
+ "Symmetric Digital Subscriber Loop";
+ }
+ enum "vdsl" {
+ value 97;
+ description
+ "Very H-Speed Digital Subscrib. Loop";
+ }
+ enum "iso88025CRFPInt" {
+ value 98;
+ description
+ "ISO 802.5 CRFP";
+ }
+ enum "myrinet" {
+ value 99;
+ description
+ "Myricom Myrinet";
+ }
+ enum "voiceEM" {
+ value 100;
+ description
+ "voice recEive and transMit";
+ }
+ enum "voiceFXO" {
+ value 101;
+ description
+ "voice Foreign Exchange Office";
+ }
+ enum "voiceFXS" {
+ value 102;
+ description
+ "voice Foreign Exchange Station";
+ }
+ enum "voiceEncap" {
+ value 103;
+ description
+ "voice encapsulation";
+ }
+ enum "voiceOverIp" {
+ value 104;
+ description
+ "voice over IP encapsulation";
+ }
+ enum "atmDxi" {
+ value 105;
+ description
+ "ATM DXI";
+ }
+ enum "atmFuni" {
+ value 106;
+ description
+ "ATM FUNI";
+ }
+ enum "atmIma" {
+ value 107;
+ description
+ "ATM IMA";
+ }
+ enum "pppMultilinkBundle" {
+ value 108;
+ description
+ "PPP Multilink Bundle";
+ }
+ enum "ipOverCdlc" {
+ value 109;
+ description
+ "IBM ipOverCdlc";
+ }
+ enum "ipOverClaw" {
+ value 110;
+ description
+ "IBM Common Link Access to Workstn";
+ }
+ enum "stackToStack" {
+ value 111;
+ description
+ "IBM stackToStack";
+ }
+ enum "virtualIpAddress" {
+ value 112;
+ description
+ "IBM VIPA";
+ }
+ enum "mpc" {
+ value 113;
+ description
+ "IBM multi-protocol channel support";
+ }
+ enum "ipOverAtm" {
+ value 114;
+ description
+ "IBM ipOverAtm";
+ reference
+ "RFC 2320 - Definitions of Managed Objects for Classical IP
+ and ARP Over ATM Using SMIv2 (IPOA-MIB)";
+ }
+ enum "iso88025Fiber" {
+ value 115;
+ description
+ "ISO 802.5j Fiber Token Ring";
+ }
+ enum "tdlc" {
+ value 116;
+ description
+ "IBM twinaxial data link control";
+ }
+ enum "gigabitEthernet" {
+ value 117;
+ status deprecated;
+ description
+ "Obsoleted via RFC3635
+ ethernetCsmacd(6) should be used instead";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types.";
+ }
+ enum "hdlc" {
+ value 118;
+ description
+ "HDLC";
+ }
+ enum "lapf" {
+ value 119;
+ description
+ "LAP F";
+ }
+ enum "v37" {
+ value 120;
+ description
+ "V.37";
+ }
+ enum "x25mlp" {
+ value 121;
+ description
+ "Multi-Link Protocol";
+ }
+ enum "x25huntGroup" {
+ value 122;
+ description
+ "X25 Hunt Group";
+ }
+ enum "transpHdlc" {
+ value 123;
+ description
+ "Transp HDLC";
+ }
+ enum "interleave" {
+ value 124;
+ description
+ "Interleave channel";
+ }
+ enum "fast" {
+ value 125;
+ description
+ "Fast channel";
+ }
+ enum "ip" {
+ value 126;
+ description
+ "IP (for APPN HPR in IP networks)";
+ }
+ enum "docsCableMaclayer" {
+ value 127;
+ description
+ "CATV Mac Layer";
+ }
+ enum "docsCableDownstream" {
+ value 128;
+ description
+ "CATV Downstream interface";
+ }
+ enum "docsCableUpstream" {
+ value 129;
+ description
+ "CATV Upstream interface";
+ }
+ enum "a12MppSwitch" {
+ value 130;
+ description
+ "Avalon Parallel Processor";
+ }
+ enum "tunnel" {
+ value 131;
+ description
+ "Encapsulation interface";
+ }
+ enum "coffee" {
+ value 132;
+ description
+ "coffee pot";
+ reference
+ "RFC 2325 - Coffee MIB";
+ }
+ enum "ces" {
+ value 133;
+ description
+ "Circuit Emulation Service";
+ }
+ enum "atmSubInterface" {
+ value 134;
+ description
+ "ATM Sub Interface";
+ }
+ enum "l2vlan" {
+ value 135;
+ description
+ "Layer 2 Virtual LAN using 802.1Q";
+ }
+ enum "l3ipvlan" {
+ value 136;
+ description
+ "Layer 3 Virtual LAN using IP";
+ }
+ enum "l3ipxvlan" {
+ value 137;
+ description
+ "Layer 3 Virtual LAN using IPX";
+ }
+ enum "digitalPowerline" {
+ value 138;
+ description
+ "IP over Power Lines";
+ }
+ enum "mediaMailOverIp" {
+ value 139;
+ description
+ "Multimedia Mail over IP";
+ }
+ enum "dtm" {
+ value 140;
+ description
+ "Dynamic syncronous Transfer Mode";
+ }
+ enum "dcn" {
+ value 141;
+ description
+ "Data Communications Network";
+ }
+ enum "ipForward" {
+ value 142;
+ description
+ "IP Forwarding Interface";
+ }
+ enum "msdsl" {
+ value 143;
+ description
+ "Multi-rate Symmetric DSL";
+ }
+ enum "ieee1394" {
+ value 144;
+ description
+ "IEEE1394 High Performance Serial Bus";
+ }
+ enum "if-gsn" {
+ value 145;
+ description
+ "HIPPI-6400";
+ }
+ enum "dvbRccMacLayer" {
+ value 146;
+ description
+ "DVB-RCC MAC Layer";
+ }
+ enum "dvbRccDownstream" {
+ value 147;
+ description
+ "DVB-RCC Downstream Channel";
+ }
+ enum "dvbRccUpstream" {
+ value 148;
+ description
+ "DVB-RCC Upstream Channel";
+ }
+ enum "atmVirtual" {
+ value 149;
+ description
+ "ATM Virtual Interface";
+ }
+ enum "mplsTunnel" {
+ value 150;
+ description
+ "MPLS Tunnel Virtual Interface";
+ }
+ enum "srp" {
+ value 151;
+ description
+ "Spatial Reuse Protocol";
+ }
+ enum "voiceOverAtm" {
+ value 152;
+ description
+ "Voice Over ATM";
+ }
+ enum "voiceOverFrameRelay" {
+ value 153;
+ description
+ "Voice Over Frame Relay";
+ }
+ enum "idsl" {
+ value 154;
+ description
+ "Digital Subscriber Loop over ISDN";
+ }
+ enum "compositeLink" {
+ value 155;
+ description
+ "Avici Composite Link Interface";
+ }
+ enum "ss7SigLink" {
+ value 156;
+ description
+ "SS7 Signaling Link";
+ }
+ enum "propWirelessP2P" {
+ value 157;
+ description
+ "Prop. P2P wireless interface";
+ }
+ enum "frForward" {
+ value 158;
+ description
+ "Frame Forward Interface";
+ }
+ enum "rfc1483" {
+ value 159;
+ description
+ "Multiprotocol over ATM AAL5";
+ reference
+ "RFC 1483 - Multiprotocol Encapsulation over ATM
+ Adaptation Layer 5";
+ }
+ enum "usb" {
+ value 160;
+ description
+ "USB Interface";
+ }
+ enum "ieee8023adLag" {
+ value 161;
+ description
+ "IEEE 802.3ad Link Aggregate";
+ }
+ enum "bgppolicyaccounting" {
+ value 162;
+ description
+ "BGP Policy Accounting";
+ }
+ enum "frf16MfrBundle" {
+ value 163;
+ description
+ "FRF .16 Multilink Frame Relay";
+ }
+ enum "h323Gatekeeper" {
+ value 164;
+ description
+ "H323 Gatekeeper";
+ }
+ enum "h323Proxy" {
+ value 165;
+ description
+ "H323 Voice and Video Proxy";
+ }
+ enum "mpls" {
+ value 166;
+ description
+ "MPLS";
+ }
+ enum "mfSigLink" {
+ value 167;
+ description
+ "Multi-frequency signaling link";
+ }
+ enum "hdsl2" {
+ value 168;
+ description
+ "High Bit-Rate DSL - 2nd generation";
+ }
+ enum "shdsl" {
+ value 169;
+ description
+ "Multirate HDSL2";
+ }
+ enum "ds1FDL" {
+ value 170;
+ description
+ "Facility Data Link 4Kbps on a DS1";
+ }
+ enum "pos" {
+ value 171;
+ description
+ "Packet over SONET/SDH Interface";
+ }
+ enum "dvbAsiIn" {
+ value 172;
+ description
+ "DVB-ASI Input";
+ }
+ enum "dvbAsiOut" {
+ value 173;
+ description
+ "DVB-ASI Output";
+ }
+ enum "plc" {
+ value 174;
+ description
+ "Power Line Communtications";
+ }
+ enum "nfas" {
+ value 175;
+ description
+ "Non Facility Associated Signaling";
+ }
+ enum "tr008" {
+ value 176;
+ description
+ "TR008";
+ }
+ enum "gr303RDT" {
+ value 177;
+ description
+ "Remote Digital Terminal";
+ }
+ enum "gr303IDT" {
+ value 178;
+ description
+ "Integrated Digital Terminal";
+ }
+ enum "isup" {
+ value 179;
+ description
+ "ISUP";
+ }
+ enum "propDocsWirelessMaclayer" {
+ value 180;
+ description
+ "Cisco proprietary Maclayer";
+ }
+ enum "propDocsWirelessDownstream" {
+ value 181;
+ description
+ "Cisco proprietary Downstream";
+ }
+ enum "propDocsWirelessUpstream" {
+ value 182;
+ description
+ "Cisco proprietary Upstream";
+ }
+ enum "hiperlan2" {
+ value 183;
+ description
+ "HIPERLAN Type 2 Radio Interface";
+ }
+ enum "propBWAp2Mp" {
+ value 184;
+ description
+ "PropBroadbandWirelessAccesspt2multipt use of this value
+ for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f
+ is deprecated and ieee80216WMAN(237) should be used
+ instead.";
+ }
+ enum "sonetOverheadChannel" {
+ value 185;
+ description
+ "SONET Overhead Channel";
+ }
+ enum "digitalWrapperOverheadChannel" {
+ value 186;
+ description
+ "Digital Wrapper";
+ }
+ enum "aal2" {
+ value 187;
+ description
+ "ATM adaptation layer 2";
+ }
+ enum "radioMAC" {
+ value 188;
+ description
+ "MAC layer over radio links";
+ }
+ enum "atmRadio" {
+ value 189;
+ description
+ "ATM over radio links";
+ }
+ enum "imt" {
+ value 190;
+ description
+ "Inter Machine Trunks";
+ }
+ enum "mvl" {
+ value 191;
+ description
+ "Multiple Virtual Lines DSL";
+ }
+ enum "reachDSL" {
+ value 192;
+ description
+ "Long Reach DSL";
+ }
+ enum "frDlciEndPt" {
+ value 193;
+ description
+ "Frame Relay DLCI End Point";
+ }
+ enum "atmVciEndPt" {
+ value 194;
+ description
+ "ATM VCI End Point";
+ }
+ enum "opticalChannel" {
+ value 195;
+ description
+ "Optical Channel";
+ }
+ enum "opticalTransport" {
+ value 196;
+ description
+ "Optical Transport";
+ }
+ enum "propAtm" {
+ value 197;
+ description
+ "Proprietary ATM";
+ }
+ enum "voiceOverCable" {
+ value 198;
+ description
+ "Voice Over Cable Interface";
+ }
+ enum "infiniband" {
+ value 199;
+ description
+ "Infiniband";
+ }
+ enum "teLink" {
+ value 200;
+ description
+ "TE Link";
+ }
+ enum "q2931" {
+ value 201;
+ description
+ "Q.2931";
+ }
+ enum "virtualTg" {
+ value 202;
+ description
+ "Virtual Trunk Group";
+ }
+ enum "sipTg" {
+ value 203;
+ description
+ "SIP Trunk Group";
+ }
+ enum "sipSig" {
+ value 204;
+ description
+ "SIP Signaling";
+ }
+ enum "docsCableUpstreamChannel" {
+ value 205;
+ description
+ "CATV Upstream Channel";
+ }
+ enum "econet" {
+ value 206;
+ description
+ "Acorn Econet";
+ }
+ enum "pon155" {
+ value 207;
+ description
+ "FSAN 155Mb Symetrical PON interface";
+ }
+ enum "pon622" {
+ value 208;
+ description
+ "FSAN622Mb Symetrical PON interface";
+ }
+ enum "bridge" {
+ value 209;
+ description
+ "Transparent bridge interface";
+ }
+ enum "linegroup" {
+ value 210;
+ description
+ "Interface common to multiple lines";
+ }
+ enum "voiceEMFGD" {
+ value 211;
+ description
+ "voice E&M Feature Group D";
+ }
+ enum "voiceFGDEANA" {
+ value 212;
+ description
+ "voice FGD Exchange Access North American";
+ }
+ enum "voiceDID" {
+ value 213;
+ description
+ "voice Direct Inward Dialing";
+ }
+ enum "mpegTransport" {
+ value 214;
+ description
+ "MPEG transport interface";
+ }
+ enum "sixToFour" {
+ value 215;
+ status deprecated;
+ description
+ "6to4 interface (DEPRECATED)";
+ reference
+ "RFC 4087 - IP Tunnel MIB";
+ }
+ enum "gtp" {
+ value 216;
+ description
+ "GTP (GPRS Tunneling Protocol)";
+ }
+ enum "pdnEtherLoop1" {
+ value 217;
+ description
+ "Paradyne EtherLoop 1";
+ }
+ enum "pdnEtherLoop2" {
+ value 218;
+ description
+ "Paradyne EtherLoop 2";
+ }
+ enum "opticalChannelGroup" {
+ value 219;
+ description
+ "Optical Channel Group";
+ }
+ enum "homepna" {
+ value 220;
+ description
+ "HomePNA ITU-T G.989";
+ }
+ enum "gfp" {
+ value 221;
+ description
+ "Generic Framing Procedure (GFP)";
+ }
+ enum "ciscoISLvlan" {
+ value 222;
+ description
+ "Layer 2 Virtual LAN using Cisco ISL";
+ }
+ enum "actelisMetaLOOP" {
+ value 223;
+ description
+ "Acteleis proprietary MetaLOOP High Speed Link";
+ }
+ enum "fcipLink" {
+ value 224;
+ description
+ "FCIP Link";
+ }
+ enum "rpr" {
+ value 225;
+ description
+ "Resilient Packet Ring Interface Type";
+ }
+ enum "qam" {
+ value 226;
+ description
+ "RF Qam Interface";
+ }
+ enum "lmp" {
+ value 227;
+ description
+ "Link Management Protocol";
+ reference
+ "RFC 4327 - Link Management Protocol (LMP) Management
+ Information Base (MIB)";
+ }
+ enum "cblVectaStar" {
+ value 228;
+ description
+ "Cambridge Broadband Networks Limited VectaStar";
+ }
+ enum "docsCableMCmtsDownstream" {
+ value 229;
+ description
+ "CATV Modular CMTS Downstream Interface";
+ }
+ enum "adsl2" {
+ value 230;
+ status deprecated;
+ description
+ "Asymmetric Digital Subscriber Loop Version 2
+ (DEPRECATED/OBSOLETED - please use adsl2plus(238)
+ instead)";
+ reference
+ "RFC 4706 - Definitions of Managed Objects for Asymmetric
+ Digital Subscriber Line 2 (ADSL2)";
+ }
+ enum "macSecControlledIF" {
+ value 231;
+ description
+ "MACSecControlled";
+ }
+ enum "macSecUncontrolledIF" {
+ value 232;
+ description
+ "MACSecUncontrolled";
+ }
+ enum "aviciOpticalEther" {
+ value 233;
+ description
+ "Avici Optical Ethernet Aggregate";
+ }
+ enum "atmbond" {
+ value 234;
+ description
+ "atmbond";
+ }
+ enum "voiceFGDOS" {
+ value 235;
+ description
+ "voice FGD Operator Services";
+ }
+ enum "mocaVersion1" {
+ value 236;
+ description
+ "MultiMedia over Coax Alliance (MoCA) Interface
+ as documented in information provided privately to IANA";
+ }
+ enum "ieee80216WMAN" {
+ value 237;
+ description
+ "IEEE 802.16 WMAN interface";
+ }
+ enum "adsl2plus" {
+ value 238;
+ description
+ "Asymmetric Digital Subscriber Loop Version 2,
+ Version 2 Plus and all variants";
+ }
+ enum "dvbRcsMacLayer" {
+ value 239;
+ description
+ "DVB-RCS MAC Layer";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "dvbTdm" {
+ value 240;
+ description
+ "DVB Satellite TDM";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "dvbRcsTdma" {
+ value 241;
+ description
+ "DVB-RCS TDMA";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ enum "x86Laps" {
+ value 242;
+ description
+ "LAPS based on ITU-T X.86/Y.1323";
+ }
+ enum "wwanPP" {
+ value 243;
+ description
+ "3GPP WWAN";
+ }
+ enum "wwanPP2" {
+ value 244;
+ description
+ "3GPP2 WWAN";
+ }
+ enum "voiceEBS" {
+ value 245;
+ description
+ "voice P-phone EBS physical interface";
+ }
+ enum "ifPwType" {
+ value 246;
+ description
+ "Pseudowire interface type";
+ reference
+ "RFC 5601 - Pseudowire (PW) Management Information Base";
+ }
+ enum "ilan" {
+ value 247;
+ description
+ "Internal LAN on a bridge per IEEE 802.1ap";
+ }
+ enum "pip" {
+ value 248;
+ description
+ "Provider Instance Port on a bridge per IEEE 802.1ah PBB";
+ }
+ enum "aluELP" {
+ value 249;
+ description
+ "Alcatel-Lucent Ethernet Link Protection";
+ }
+ enum "gpon" {
+ value 250;
+ description
+ "Gigabit-capable passive optical networks (G-PON) as per
+ ITU-T G.948";
+ }
+ enum "vdsl2" {
+ value 251;
+ description
+ "Very high speed digital subscriber line Version 2
+ (as per ITU-T Recommendation G.993.2)";
+ reference
+ "RFC 5650 - Definitions of Managed Objects for Very High
+ Speed Digital Subscriber Line 2 (VDSL2)";
+ }
+ enum "capwapDot11Profile" {
+ value 252;
+ description
+ "WLAN Profile Interface";
+ reference
+ "RFC 5834 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Binding MIB for
+ IEEE 802.11";
+ }
+ enum "capwapDot11Bss" {
+ value 253;
+ description
+ "WLAN BSS Interface";
+ reference
+ "RFC 5834 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Binding MIB for
+ IEEE 802.11";
+ }
+ enum "capwapWtpVirtualRadio" {
+ value 254;
+ description
+ "WTP Virtual Radio Interface";
+ reference
+ "RFC 5833 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Base MIB";
+ }
+ enum "bits" {
+ value 255;
+ description
+ "bitsport";
+ }
+ enum "docsCableUpstreamRfPort" {
+ value 256;
+ description
+ "DOCSIS CATV Upstream RF Port";
+ }
+ enum "cableDownstreamRfPort" {
+ value 257;
+ description
+ "CATV downstream RF port";
+ }
+ enum "vmwareVirtualNic" {
+ value 258;
+ description
+ "VMware Virtual Network Interface";
+ }
+ enum "ieee802154" {
+ value 259;
+ description
+ "IEEE 802.15.4 WPAN interface";
+ reference
+ "IEEE 802.15.4-2006";
+ }
+ enum "otnOdu" {
+ value 260;
+ description
+ "OTN Optical Data Unit";
+ }
+ enum "otnOtu" {
+ value 261;
+ description
+ "OTN Optical channel Transport Unit";
+ }
+ enum "ifVfiType" {
+ value 262;
+ description
+ "VPLS Forwarding Instance Interface Type";
+ }
+ enum "g9981" {
+ value 263;
+ description
+ "G.998.1 bonded interface";
+ }
+ enum "g9982" {
+ value 264;
+ description
+ "G.998.2 bonded interface";
+ }
+ enum "g9983" {
+ value 265;
+ description
+ "G.998.3 bonded interface";
+ }
+ enum "aluEpon" {
+ value 266;
+ description
+ "Ethernet Passive Optical Networks (E-PON)";
+ }
+ enum "aluEponOnu" {
+ value 267;
+ description
+ "EPON Optical Network Unit";
+ }
+ enum "aluEponPhysicalUni" {
+ value 268;
+ description
+ "EPON physical User to Network interface";
+ }
+ enum "aluEponLogicalLink" {
+ value 269;
+ description
+ "The emulation of a point-to-point link over the EPON
+ layer";
+ }
+ enum "aluGponOnu" {
+ value 270;
+ description
+ "GPON Optical Network Unit";
+ reference
+ "ITU-T G.984.2";
+ }
+ enum "aluGponPhysicalUni" {
+ value 271;
+ description
+ "GPON physical User to Network interface";
+ reference
+ "ITU-T G.984.2";
+ }
+ enum "vmwareNicTeam" {
+ value 272;
+ description
+ "VMware NIC Team";
+ }
+ // value 273 reserved by IANA
+ }
+ description
+ "This data type is used as the syntax of the 'type'
+ leaf in the 'interface' list in the YANG module
+ ietf-interface.
+
+ The definition of this typedef with the
+ addition of newly assigned values is published
+ periodically by the IANA, in either the Assigned
+ Numbers RFC, or some derivative of it specific to
+ Internet Network Management number assignments. (The
+ latest arrangements can be obtained by contacting the
+ IANA.)
+
+ Requests for new values should be made to IANA via
+ email (iana&iana.org).";
+ reference
+ "IANA ifType definitions registry.
+ <http://www.iana.org/assignments/smi-numbers>";
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-inet-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-inet-types.yang
new file mode 100644
index 0000000..de20feb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-inet-types.yang
@@ -0,0 +1,418 @@
+ module ietf-inet-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+ prefix "inet";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ typedef ip-version {
+ type enumeration {
+ enum unknown {
+ value "0";
+ description
+ "An unknown or unspecified version of the Internet protocol.";
+ }
+ enum ipv4 {
+ value "1";
+ description
+ "The IPv4 protocol as defined in RFC 791.";
+ }
+ enum ipv6 {
+ value "2";
+ description
+ "The IPv6 protocol as defined in RFC 2460.";
+ }
+ }
+ description
+ "This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.";
+ reference
+ "RFC 791: Internet Protocol
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ typedef dscp {
+ type uint8 {
+ range "0..63";
+ }
+ description
+ "The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.";
+ reference
+ "RFC 3289: Management Information Base for the Differentiated
+ Services Architecture
+ RFC 2474: Definition of the Differentiated Services Field
+ (DS Field) in the IPv4 and IPv6 Headers
+ RFC 2780: IANA Allocation Guidelines For Values In
+ the Internet Protocol and Related Headers";
+ }
+
+ typedef ipv6-flow-label {
+ type uint32 {
+ range "0..1048575";
+ }
+ description
+ "The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.";
+ reference
+ "RFC 3595: Textual Conventions for IPv6 Flow Label
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+ }
+
+ typedef port-number {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.";
+ reference
+ "RFC 768: User Datagram Protocol
+ RFC 793: Transmission Control Protocol
+ RFC 4960: Stream Control Transmission Protocol
+ RFC 4340: Datagram Congestion Control Protocol (DCCP)
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of autonomous system related types ***/
+
+ typedef as-number {
+ type uint32;
+ description
+ "The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.";
+ reference
+ "RFC 1930: Guidelines for creation, selection, and registration
+ of an Autonomous System (AS)
+ RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+ RFC 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ typedef ip-address {
+ type union {
+ type inet:ipv4-address;
+ type inet:ipv6-address;
+ }
+ description
+ "The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '(%[\p{N}\p{L}]+)?';
+ }
+ description
+ "The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format";
+ }
+
+ typedef ipv6-address {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(%[\p{N}\p{L}]+)?';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(%.+)?';
+ }
+ description
+ "The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture
+ RFC 4007: IPv6 Scoped Address Architecture
+ RFC 5952: A Recommendation for IPv6 Address Text Representation";
+ }
+
+ typedef ip-prefix {
+ type union {
+ type inet:ipv4-prefix;
+ type inet:ipv6-prefix;
+ }
+ description
+ "The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-prefix {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+ }
+ description
+ "The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.";
+ }
+
+ typedef ipv6-prefix {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(/.+)';
+ }
+ description
+ "The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** collection of domain name and URI types ***/
+
+ typedef domain-name {
+ type string {
+ pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ + '|\.';
+ length "1..253";
+ }
+ description
+ "The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492";
+ reference
+ "RFC 952: DoD Internet Host Table Specification
+ RFC 1034: Domain Names - Concepts and Facilities
+ RFC 1123: Requirements for Internet Hosts -- Application
+ and Support
+ RFC 2782: A DNS RR for specifying the location of services
+ (DNS SRV)
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ typedef host {
+ type union {
+ type inet:ip-address;
+ type inet:domain-name;
+ }
+ description
+ "The host type represents either an IP address or a DNS
+ domain name.";
+ }
+
+ typedef uri {
+ type string;
+ description
+ "The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.";
+ reference
+ "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+ Group: Uniform Resource Identifiers (URIs), URLs,
+ and Uniform Resource Names (URNs): Clarifications
+ and Recommendations
+ RFC 5017: MIB Textual Conventions for Uniform Resource
+ Identifiers (URIs)";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-interfaces@2013-07-04.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-interfaces@2013-07-04.yang
new file mode 100644
index 0000000..9db753c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-interfaces@2013-07-04.yang
@@ -0,0 +1,673 @@
+module ietf-interfaces {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+ prefix if;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import iana-if-type {
+ prefix ianaift;
+ }
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ WG Chair: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>";
+
+ description
+ "This module contains a collection of YANG definitions for
+ managing network interfaces.
+
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-07-04 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: A YANG Data Model for Interface Management";
+ }
+
+ /* Typedefs */
+
+ typedef interface-ref {
+ type leafref {
+ path "/if:interfaces/if:interface/if:name";
+ }
+ description
+ "This type is used by data models that need to reference
+ configured interfaces.";
+ }
+
+ typedef interface-state-ref {
+ type leafref {
+ path "/if:interfaces-state/if:interface/if:name";
+ }
+ description
+ "This type is used by data models that need to reference
+ the operationally present interfaces.";
+ }
+
+ /* Features */
+
+ feature arbitrary-names {
+ description
+ "This feature indicates that the device allows user-controlled
+ interfaces to be named arbitrarily.";
+ }
+
+ feature pre-provisioning {
+ description
+ "This feature indicates that the device supports
+ pre-provisioning of interface configuration, i.e., it is
+ possible to configure an interface whose physical interface
+ hardware is not present on the device.";
+ }
+
+ feature if-mib {
+ description
+ "This feature indicates that the device implements IF-MIB.";
+ reference
+ "RFC 2863: The Interfaces Group MIB";
+ }
+
+ /* Data nodes */
+
+ container interfaces {
+ description
+ "Interface configuration parameters.";
+
+ list interface {
+ key "name";
+
+ description
+ "The list of configured interfaces on the device.
+
+ The operational state of an interface is available in the
+ /interfaces-state/interface list. If the configuration of a
+ system-controlled interface cannot be used by the system
+ (e.g., the interface hardware present does not match the
+ interface type), then the configuration is not applied to
+ the system-controlled interface shown in the
+ /interfaces-state/interface list. If the the configuration
+ of a user-controlled interface cannot be used by the system,
+ the configured interface is not instantiated in the
+ /interfaces-state/interface list.";
+
+ leaf name {
+ type string;
+ description
+ "The name of the interface.
+
+ A device MAY restrict the allowed values for this leaf,
+ possibly depending on the type of the interface.
+
+ For system-controlled interfaces, this leaf is the
+ device-specific name of the interface. The 'config false'
+ list /interfaces-state/interface contains the currently
+ existing interfaces on the device.
+
+ If a client tries to create configuration for a
+ system-controlled interface that is not present in the
+ /interfaces-state/interface list, the server MAY reject
+ the request, if the implementation does not support
+ pre-provisioning of interfaces, or if the name refers to
+ an interface that can never exist in the system. A
+ NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.
+
+ If the device supports pre-provisioning of interface
+ configuration, the feature 'pre-provisioning' is
+ advertised.
+
+ If the device allows arbitrarily named user-controlled
+ interfaces, the feature 'arbitrary-names' is advertised.
+
+ When a configured user-controlled interface is created by
+ the system, it is instantiated with the same name in the
+ /interface-state/interface list. Since the name in that
+ list MAY be mapped to ifName by an implementation, such an
+ implementation MUST restrict the allowed values for this
+ leaf so that it matches the restrictions of ifName.
+
+ If a NETCONF server that implements this restriction is
+ sent a value that doesn't match the restriction, it MUST
+ reply with an rpc-error with the error-tag
+ 'invalid-value'.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "A textual description of the interface.
+
+ This leaf MAY be mapped to ifAlias by an implementation.
+ Such an implementation MUST restrict the allowed values
+ for this leaf so that it matches the restrictions of
+ ifAlias.
+
+ If a NETCONF server that implements this restriction is
+ sent a value that doesn't match the restriction, it MUST
+ reply with an rpc-error with the error-tag
+ 'invalid-value'.
+
+ Since ifAlias is defined to be stored in non-volatile
+ storage, the MIB implementation MUST map ifAlias to the
+ value of 'description' in the persistently stored
+ datastore.
+
+ Specifically, if the device supports ':startup', when
+ ifAlias is read the device MUST return the value of
+ 'description' in the 'startup' datastore, and when it is
+ written, it MUST be written to the 'running' and 'startup'
+ datastores. Note that it is up to the implementation if
+ it modifies this single leaf in 'startup', or if it
+ performs an implicit copy-config from 'running' to
+ 'startup'.
+
+ If the device does not support ':startup', ifAlias MUST
+ be mapped to the 'description' leaf in the 'running'
+ datastore.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAlias";
+ }
+
+ leaf type {
+ type ianaift:iana-if-type;
+ mandatory true;
+ description
+ "The type of the interface.
+
+ When an interface entry is created, a server MAY
+ initialize the type leaf with a valid value, e.g., if it
+ is possible to derive the type from the name of the
+ interface.
+
+ If a client tries to set the type of an interface to a
+ value that can never be used by the system, e.g., if the
+ type is not supported or if the type does not match the
+ name of the interface, the server MUST reject the request.
+ A NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf enabled {
+ type boolean;
+ default "true";
+ description
+ "This leaf contains the configured, desired state of the
+ interface.
+
+ Systems that implement the IF-MIB use the value of this
+ leaf in the 'running' datastore to set
+ IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
+ has been initialized, as described in RFC 2863.
+
+ Changes in this leaf in the 'running' datastore are
+ reflected in ifAdminStatus, but if ifAdminStatus is
+ changed over SNMP, this leaf is not affected.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf link-up-down-trap-enable {
+ if-feature if-mib;
+ type enumeration {
+ enum enabled {
+ value 1;
+ }
+ enum disabled {
+ value 2;
+ }
+ }
+ description
+ "Controls whether linkUp/linkDown SNMP notifications
+ should be generated for this interface.
+
+ If this node is not configured, the value 'enabled' is
+ operationally used by the server for interfaces which do
+ not operate on top of any other interface (i.e., there are
+ no 'lower-layer-if' entries), and 'disabled' otherwise.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifLinkUpDownTrapEnable";
+ }
+ }
+ }
+
+ container interfaces-state {
+ config false;
+ description
+ "Data nodes for the operational state of interfaces.";
+
+ list interface {
+ key "name";
+
+ description
+ "The list of interfaces on the device.
+
+ System-controlled interfaces created by the system are
+ always present in this list, whether they are configured or
+ not.";
+
+ leaf name {
+ type string;
+ description
+ "The name of the interface.
+
+ This leaf MAY be mapped to ifName by an implementation.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifName";
+ }
+
+ leaf type {
+ type ianaift:iana-if-type;
+ mandatory true;
+ description
+ "The type of the interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf admin-status {
+ if-feature if-mib;
+ type enumeration {
+ enum up {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum down {
+ value 2;
+ description
+ "Not ready to pass packets and not in some test mode.";
+ }
+ enum testing {
+ value 3;
+ description
+ "In some test mode.";
+ }
+ }
+ mandatory true;
+ description
+ "The desired state of the interface.
+
+ This leaf has the same read semantics as ifAdminStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf oper-status {
+ type enumeration {
+ enum up {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum down {
+ value 2;
+ description
+ "The interface does not pass any packets.";
+ }
+ enum testing {
+ value 3;
+ description
+ "In some test mode. No operational packets can
+ be passed.";
+ }
+ enum unknown {
+ value 4;
+ description
+ "Status cannot be determined for some reason.";
+ }
+ enum dormant {
+ value 5;
+ description
+ "Waiting for some external event.";
+ }
+ enum not-present {
+ value 6;
+ description
+ "Some component (typically hardware) is missing.";
+ }
+ enum lower-layer-down {
+ value 7;
+ description
+ "Down due to state of lower-layer interface(s).";
+ }
+ }
+ mandatory true;
+ description
+ "The current operational state of the interface.
+
+ This leaf has the same semantics as ifOperStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOperStatus";
+ }
+
+ leaf last-change {
+ type yang:date-and-time;
+ description
+ "The time the interface entered its current operational
+ state. If the current state was entered prior to the
+ last re-initialization of the local network management
+ subsystem, then this node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifLastChange";
+ }
+
+ leaf if-index {
+ if-feature if-mib;
+ type int32 {
+ range "1..2147483647";
+ }
+ mandatory true;
+ description
+ "The ifIndex value for the ifEntry represented by this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifIndex";
+ }
+
+ leaf phys-address {
+ type yang:phys-address;
+ description
+ "The interface's address at its protocol sub-layer. For
+ example, for an 802.x interface, this object normally
+ contains a MAC address. The interface's media-specific
+ modules must define the bit and byte ordering and the
+ format of the value of this object. For interfaces that do
+ not have such an address (e.g., a serial line), this node
+ is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifPhysAddress";
+ }
+
+ leaf-list higher-layer-if {
+ type interface-state-ref;
+ description
+ "A list of references to interfaces layered on top of this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifStackTable";
+ }
+
+ leaf-list lower-layer-if {
+ type interface-state-ref;
+ description
+ "A list of references to interfaces layered underneath this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifStackTable";
+ }
+
+ leaf speed {
+ type yang:gauge64;
+ units "bits / second";
+ description
+ "An estimate of the interface's current bandwidth in bits
+ per second. For interfaces that do not vary in
+ bandwidth or for those where no accurate estimation can
+ be made, this node should contain the nominal bandwidth.
+ For interfaces that have no concept of bandwidth, this
+ node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifSpeed, ifHighSpeed";
+ }
+
+ container statistics {
+ description
+ "A collection of interface-related statistics objects.";
+
+ leaf discontinuity-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time on the most recent occasion at which any one or
+ more of this interface's counters suffered a
+ discontinuity. If no such discontinuities have occurred
+ since the last re-initialization of the local management
+ subsystem, then this node contains the time the local
+ management subsystem re-initialized itself.";
+ }
+
+ leaf in-octets {
+ type yang:counter64;
+ description
+ "The total number of octets received on the interface,
+ including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInOctets";
+ }
+ leaf in-unicast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were not addressed to a
+ multicast or broadcast address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
+ }
+ leaf in-broadcast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were addressed to a broadcast
+ address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInBroadcastPkts";
+ }
+ leaf in-multicast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, which were addressed to a multicast
+ address at this sub-layer. For a MAC layer protocol,
+ this includes both Group and Functional addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInMulticastPkts";
+ }
+ leaf in-discards {
+ type yang:counter32;
+ description
+ "The number of inbound packets which were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being deliverable to a higher-layer
+ protocol. One possible reason for discarding such a
+ packet could be to free up buffer space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInDiscards";
+ }
+ leaf in-errors {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of inbound
+ packets that contained errors preventing them from being
+ deliverable to a higher-layer protocol. For character-
+ oriented or fixed-length interfaces, the number of
+ inbound transmission units that contained errors
+ preventing them from being deliverable to a higher-layer
+ protocol.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInErrors";
+ }
+ leaf in-unknown-protos {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of packets
+ received via the interface which were discarded because
+ of an unknown or unsupported protocol. For
+ character-oriented or fixed-length interfaces that
+ support protocol multiplexing the number of transmission
+ units received via the interface which were discarded
+ because of an unknown or unsupported protocol. For any
+ interface that does not support protocol multiplexing,
+ this counter is not present.
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
+ }
+
+ leaf out-octets {
+ type yang:counter64;
+ description
+ "The total number of octets transmitted out of the
+ interface, including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
+ }
+ leaf out-unicast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were not addressed
+ to a multicast or broadcast address at this sub-layer,
+ including those that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
+ }
+ leaf out-broadcast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were addressed to a
+ broadcast address at this sub-layer, including those
+ that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutBroadcastPkts";
+ }
+ leaf out-multicast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and which were addressed to a
+ multicast address at this sub-layer, including those
+ that were discarded or not sent. For a MAC layer
+ protocol, this includes both Group and Functional
+ addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutMulticastPkts";
+ }
+ leaf out-discards {
+ type yang:counter32;
+ description
+ "The number of outbound packets which were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being transmitted. One possible reason
+ for discarding such a packet could be to free up buffer
+ space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutDiscards";
+ }
+ leaf out-errors {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of outbound
+ packets that could not be transmitted because of errors.
+ For character-oriented or fixed-length interfaces, the
+ number of outbound transmission units that could not be
+ transmitted because of errors.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutErrors";
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-restconf-monitoring@2017-01-26.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-restconf-monitoring@2017-01-26.yang
new file mode 100644
index 0000000..55c3cb1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-restconf-monitoring@2017-01-26.yang
@@ -0,0 +1,149 @@
+module ietf-restconf-monitoring {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring";
+ prefix "rcmon";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ Author: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Author: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Author: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+
+ description
+ "This module contains monitoring information for the
+ RESTCONF protocol.
+
+ Copyright (c) 2017 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 8040; see
+ the RFC itself for full legal notices.";
+
+ revision 2017-01-26 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 8040: RESTCONF Protocol.";
+ }
+
+ container restconf-state {
+ config false;
+ description
+ "Contains RESTCONF protocol monitoring information.";
+
+ container capabilities {
+ description
+ "Contains a list of protocol capability URIs.";
+
+ leaf-list capability {
+ type inet:uri;
+ description
+ "A RESTCONF protocol capability URI.";
+ }
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description
+ "The stream name.";
+ reference
+ "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "Description of stream content.";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ default false;
+ description
+ "Indicates if replay buffer is supported for this stream.
+ If 'true', then the server MUST support the 'start-time'
+ and 'stop-time' query parameters for this stream.";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ when "../replay-support" {
+ description
+ "Only present if notification replay is supported.";
+ }
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ list access {
+ key encoding;
+ min-elements 1;
+ description
+ "The server will create an entry in this list for each
+ encoding format that is supported for this stream.
+ The media type 'text/event-stream' is expected
+ for all event streams. This list identifies the
+ subtypes supported for this stream.";
+
+ leaf encoding {
+ type string;
+ description
+ "This is the secondary encoding format within the
+ 'text/event-stream' encoding used by all streams.
+ The type 'xml' is supported for XML encoding.
+ The type 'json' is supported for JSON encoding.";
+ }
+
+ leaf location {
+ type inet:uri;
+ mandatory true;
+ description
+ "Contains a URL that represents the entry point
+ for establishing notification delivery via
+ server-sent events.";
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-restconf@2013-10-19.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-restconf@2013-10-19.yang
new file mode 100644
index 0000000..16766b0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-restconf@2013-10-19.yang
@@ -0,0 +1,684 @@
+module ietf-restconf {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ container modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one module currently
+ supported by the server.";
+
+ leaf name {
+ type yang:yang-identifier;
+ description "The YANG module name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module revision date. An empty string is
+ used if no revision statement is present in the
+ YANG module.";
+ }
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server.";
+ }
+ leaf-list deviation {
+ type yang:yang-identifier;
+ description
+ "List of YANG deviation module names used by this
+ server to modify the conformance of the module
+ associated with this entry.";
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ } \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-yang-library@2016-06-21.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-yang-library@2016-06-21.yang
new file mode 100644
index 0000000..bc466ee
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-yang-library@2016-06-21.yang
@@ -0,0 +1,208 @@
+module ietf-yang-library {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-library";
+ prefix "yanglib";
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import ietf-inet-types {
+ prefix inet;
+ }
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+ WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+ WG Chair: Mahesh Jethanandani
+ <mailto:mjethanandani@gmail.com>
+ Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+ description
+ "This module contains monitoring information about the YANG
+ modules and submodules that are used within a YANG-based
+ server.
+ Copyright (c) 2016 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+ This version of this YANG module is part of RFC 7895; see
+ the RFC itself for full legal notices.";
+ revision 2016-06-21 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 7895: YANG Module Library.";
+ }
+ /*
+ * Typedefs
+ */
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.";
+ }
+ /*
+ * Groupings
+ */
+ grouping module-list {
+ description
+ "The module data structure is represented as a grouping
+ so it can be reused in configuration or another monitoring
+ data structure.";
+ grouping common-leafs {
+ description
+ "Common parameters for YANG modules and submodules.";
+ leaf name {
+ type yang:yang-identifier;
+ description
+ "The YANG module or submodule name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module or submodule revision date.
+ A zero-length string is used if no revision statement
+ is present in the YANG module or submodule.";
+ }
+ }
+ grouping schema-leaf {
+ description
+ "Common schema leaf parameter for modules and submodules.";
+ leaf schema {
+ type inet:uri;
+ description
+ "Contains a URL that represents the YANG schema
+ resource for this module or submodule.
+ This leaf will only be present if there is a URL
+ available for retrieval of the schema for this entry.";
+ }
+ }
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one revision of one module
+ currently supported by the server.";
+ uses common-leafs;
+ uses schema-leaf;
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server, regardless of whether they are
+ defined in the module or any included submodule.";
+ }
+ list deviation {
+ key "name revision";
+ description
+ "List of YANG deviation module names and revisions
+ used by this server to modify the conformance of
+ the module associated with this entry. Note that
+ the same module can be used for deviations for
+ multiple modules, so the same entry MAY appear
+ within multiple 'module' entries.
+ The deviation module MUST be present in the 'module'
+ list, with the same name and revision values.
+ The 'conformance-type' value will be 'implement' for
+ the deviation module.";
+ uses common-leafs;
+ }
+ leaf conformance-type {
+ type enumeration {
+ enum implement {
+ description
+ "Indicates that the server implements one or more
+ protocol-accessible objects defined in the YANG module
+ identified in this entry. This includes deviation
+ statements defined in the module.
+ For YANG version 1.1 modules, there is at most one
+ module entry with conformance type 'implement' for a
+ particular module name, since YANG 1.1 requires that,
+ at most, one revision of a module is implemented.
+ For YANG version 1 modules, there SHOULD NOT be more
+ than one module entry for a particular module name.";
+ }
+ enum import {
+ description
+ "Indicates that the server imports reusable definitions
+ from the specified revision of the module but does
+ not implement any protocol-accessible objects from
+ this revision.
+ Multiple module entries for the same module name MAY
+ exist. This can occur if multiple modules import the
+ same module but specify different revision dates in
+ the import statements.";
+ }
+ }
+ mandatory true;
+ description
+ "Indicates the type of conformance the server is claiming
+ for the YANG module identified by this entry.";
+ }
+ list submodule {
+ key "name revision";
+ description
+ "Each entry represents one submodule within the
+ parent module.";
+ uses common-leafs;
+ uses schema-leaf;
+ }
+ }
+ }
+ /*
+ * Operational state data nodes
+ */
+ container modules-state {
+ config false;
+ description
+ "Contains YANG module monitoring information.";
+ leaf module-set-id {
+ type string;
+ mandatory true;
+ description
+ "Contains a server-specific identifier representing
+ the current set of modules and submodules. The
+ server MUST change the value of this leaf if the
+ information represented by the 'module' list instances
+ has changed.";
+ }
+ uses module-list;
+ }
+ /*
+ * Notifications
+ */
+ notification yang-library-change {
+ description
+ "Generated when the set of modules and submodules supported
+ by the server has changed.";
+ leaf module-set-id {
+ type leafref {
+ path "/yanglib:modules-state/yanglib:module-set-id";
+ }
+ mandatory true;
+ description
+ "Contains the module-set-id value representing the
+ set of modules and submodules supported at the server at
+ the time the notification is generated.";
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-yang-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-yang-types.yang
new file mode 100644
index 0000000..07e50b3
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/ietf-yang-types.yang
@@ -0,0 +1,417 @@
+ module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+
+
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined by the 'identifier'
+ rule in Section 12 of RFC 6020. An identifier must
+ start with an alphabetic character or an underscore
+ followed by an arbitrary sequence of alphabetic or
+ numeric characters, underscores, hyphens, or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lowercase or uppercase character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using the
+ time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually referring
+ to the notion of local time) uses the time-offset -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence happened.
+ The specific occurrence must be defined in the description
+ of any schema node defined using this type. When the specific
+ occurrence occurred prior to the last time the associated
+ timeticks attribute was zero, then the timestamp value is
+ zero. Note that this requires all timestamp values to be
+ reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/module1-behind-mount-point.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/module1-behind-mount-point.yang
new file mode 100644
index 0000000..e48184b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/module1-behind-mount-point.yang
@@ -0,0 +1,10 @@
+module module1-behind-mount-point {
+ namespace "module:1:behind:mount:point";
+ prefix "mod1bemopo";
+ revision "2014-02-03";
+
+ rpc rpc-behind-module1 {
+ }
+
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/module2-behind-mount-point.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/module2-behind-mount-point.yang
new file mode 100644
index 0000000..89b8c02
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-behind-mount-point/module2-behind-mount-point.yang
@@ -0,0 +1,9 @@
+module module2-behind-mount-point {
+ namespace "module:2:behind:mount:point";
+ prefix "mod2bemopo";
+ revision "2014-02-04";
+
+ rpc rpc-behind-module2 {
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module1.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module1.yang
new file mode 100644
index 0000000..ab9d967
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module1.yang
@@ -0,0 +1,12 @@
+module module1 {
+ namespace "module:1";
+ prefix "mod1";
+ revision "2014-01-01";
+
+ rpc dummy-rpc1-module1 {
+ }
+
+ rpc dummy-rpc2-module1 {
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module2.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module2.yang
new file mode 100644
index 0000000..fa792d7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module2.yang
@@ -0,0 +1,11 @@
+module module2 {
+ namespace "module:2";
+ prefix "mod2";
+ revision "2014-01-02";
+
+ rpc dummy-rpc1-module2 {
+ }
+
+ rpc dummy-rpc2-module2 {
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module3.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module3.yang
new file mode 100644
index 0000000..39bb690
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/module3.yang
@@ -0,0 +1,5 @@
+module module3 {
+ namespace "module:3";
+ prefix "mod3";
+ revision "2014-01-03";
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/mount-point-1.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/mount-point-1.yang
new file mode 100644
index 0000000..4963c89
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/modules-without-restconf-module/mount-point-1.yang
@@ -0,0 +1,11 @@
+module mount-point-1 {
+ namespace "mount:point:1";
+ prefix "point1";
+ revision "2016-01-01";
+
+ container cont {
+ }
+
+ list listA {
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/mount-points/mount-point-1.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/mount-points/mount-point-1.yang
new file mode 100644
index 0000000..4963c89
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/mount-points/mount-point-1.yang
@@ -0,0 +1,11 @@
+module mount-point-1 {
+ namespace "mount:point:1";
+ prefix "point1";
+ revision "2016-01-01";
+
+ container cont {
+ }
+
+ list listA {
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/mount-points/mount-point-2.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/mount-points/mount-point-2.yang
new file mode 100644
index 0000000..c748cb7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/mount-points/mount-point-2.yang
@@ -0,0 +1,8 @@
+module mount-point-2 {
+ namespace "mount:point:2";
+ prefix "point2";
+ revision "2016-01-01";
+
+ container cont {
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/nested-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/nested-module.yang
new file mode 100644
index 0000000..794859b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/nested-module.yang
@@ -0,0 +1,69 @@
+module nested-module {
+ namespace "urn:nested:module";
+ prefix "nested";
+ revision "2014-06-03";
+
+ container depth1-cont {
+ list depth2-cont1 {
+ container depth3-cont1 {
+ container depth4-cont1 {
+ leaf depth5-leaf1 {
+ type string;
+ }
+ }
+
+ leaf depth4-leaf1 {
+ type string;
+ }
+ }
+
+ leaf depth3-leaf1 {
+ type string;
+ }
+ }
+
+ /* list depth2-list2 was added to test keyed list */
+ list depth2-list2 {
+ key "depth3-lf1-key depth3-lf2-key";
+ leaf depth3-lf1-key {
+ type string;
+ }
+ leaf depth3-lf2-key {
+ type string;
+ }
+ leaf depth3-lf3 {
+ type string;
+ }
+ }
+
+ leaf-list depth2-lfLst1 {
+ type string;
+ }
+
+ container depth2-cont2 {
+ container depth3-cont2 {
+ container depth4-cont2 {
+ leaf depth5-leaf2 {
+ type string;
+ }
+ }
+
+ leaf depth4-leaf2 {
+ type string;
+ }
+ }
+
+ leaf depth3-leaf2 {
+ type string;
+ }
+ }
+
+ leaf depth2-leaf1 {
+ type string;
+ }
+ }
+
+ notification notifi{
+ description "Notifi";
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/ietf-inet-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/ietf-inet-types.yang
new file mode 100644
index 0000000..de20feb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/ietf-inet-types.yang
@@ -0,0 +1,418 @@
+ module ietf-inet-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+ prefix "inet";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ typedef ip-version {
+ type enumeration {
+ enum unknown {
+ value "0";
+ description
+ "An unknown or unspecified version of the Internet protocol.";
+ }
+ enum ipv4 {
+ value "1";
+ description
+ "The IPv4 protocol as defined in RFC 791.";
+ }
+ enum ipv6 {
+ value "2";
+ description
+ "The IPv6 protocol as defined in RFC 2460.";
+ }
+ }
+ description
+ "This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.";
+ reference
+ "RFC 791: Internet Protocol
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ typedef dscp {
+ type uint8 {
+ range "0..63";
+ }
+ description
+ "The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.";
+ reference
+ "RFC 3289: Management Information Base for the Differentiated
+ Services Architecture
+ RFC 2474: Definition of the Differentiated Services Field
+ (DS Field) in the IPv4 and IPv6 Headers
+ RFC 2780: IANA Allocation Guidelines For Values In
+ the Internet Protocol and Related Headers";
+ }
+
+ typedef ipv6-flow-label {
+ type uint32 {
+ range "0..1048575";
+ }
+ description
+ "The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.";
+ reference
+ "RFC 3595: Textual Conventions for IPv6 Flow Label
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+ }
+
+ typedef port-number {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.";
+ reference
+ "RFC 768: User Datagram Protocol
+ RFC 793: Transmission Control Protocol
+ RFC 4960: Stream Control Transmission Protocol
+ RFC 4340: Datagram Congestion Control Protocol (DCCP)
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of autonomous system related types ***/
+
+ typedef as-number {
+ type uint32;
+ description
+ "The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.";
+ reference
+ "RFC 1930: Guidelines for creation, selection, and registration
+ of an Autonomous System (AS)
+ RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+ RFC 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ typedef ip-address {
+ type union {
+ type inet:ipv4-address;
+ type inet:ipv6-address;
+ }
+ description
+ "The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '(%[\p{N}\p{L}]+)?';
+ }
+ description
+ "The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format";
+ }
+
+ typedef ipv6-address {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(%[\p{N}\p{L}]+)?';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(%.+)?';
+ }
+ description
+ "The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture
+ RFC 4007: IPv6 Scoped Address Architecture
+ RFC 5952: A Recommendation for IPv6 Address Text Representation";
+ }
+
+ typedef ip-prefix {
+ type union {
+ type inet:ipv4-prefix;
+ type inet:ipv6-prefix;
+ }
+ description
+ "The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-prefix {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+ }
+ description
+ "The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.";
+ }
+
+ typedef ipv6-prefix {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(/.+)';
+ }
+ description
+ "The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** collection of domain name and URI types ***/
+
+ typedef domain-name {
+ type string {
+ pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ + '|\.';
+ length "1..253";
+ }
+ description
+ "The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492";
+ reference
+ "RFC 952: DoD Internet Host Table Specification
+ RFC 1034: Domain Names - Concepts and Facilities
+ RFC 1123: Requirements for Internet Hosts -- Application
+ and Support
+ RFC 2782: A DNS RR for specifying the location of services
+ (DNS SRV)
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ typedef host {
+ type union {
+ type inet:ip-address;
+ type inet:domain-name;
+ }
+ description
+ "The host type represents either an IP address or a DNS
+ domain name.";
+ }
+
+ typedef uri {
+ type string;
+ description
+ "The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.";
+ reference
+ "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+ Group: Uniform Resource Identifiers (URIs), URLs,
+ and Uniform Resource Names (URNs): Clarifications
+ and Recommendations
+ RFC 5017: MIB Textual Conventions for Uniform Resource
+ Identifiers (URIs)";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/ietf-yang-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/ietf-yang-types.yang
new file mode 100644
index 0000000..c3f952c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/ietf-yang-types.yang
@@ -0,0 +1,417 @@
+ module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+
+
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined by the 'identifier'
+ rule in Section 12 of RFC 6020. An identifier must
+ start with an alphabetic character or an underscore
+ followed by an arbitrary sequence of alphabetic or
+ numeric characters, underscores, hyphens, or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lowercase or uppercase character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using the
+ time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually referring
+ to the notion of local time) uses the time-offset -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence happened.
+ The specific occurrence must be defined in the description
+ of any schema node defined using this type. When the specific
+ occurrence occurred prior to the last time the associated
+ timeticks attribute was zero, then the timestamp value is
+ zero. Note that this requires all timestamp values to be
+ reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/mount-point-1.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/mount-point-1.yang
new file mode 100644
index 0000000..4963c89
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/mount-point-1.yang
@@ -0,0 +1,11 @@
+module mount-point-1 {
+ namespace "mount:point:1";
+ prefix "point1";
+ revision "2016-01-01";
+
+ container cont {
+ }
+
+ list listA {
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-container-modules/restconf-module-with-illegal-container-modules.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-container-modules/restconf-module-with-illegal-container-modules.yang
new file mode 100644
index 0000000..116cdc1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-container-modules/restconf-module-with-illegal-container-modules.yang
@@ -0,0 +1,685 @@
+module restconf-module-with-illegal-container-modules {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ /** changed from container modules to list modules for testing purposes **/
+ list modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one module currently
+ supported by the server.";
+
+ leaf name {
+ type yang:yang-identifier;
+ description "The YANG module name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module revision date. An empty string is
+ used if no revision statement is present in the
+ YANG module.";
+ }
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server.";
+ }
+ leaf-list deviation {
+ type yang:yang-identifier;
+ description
+ "List of YANG deviation module names used by this
+ server to modify the conformance of the module
+ associated with this entry.";
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ } \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-list-module/restconf-module-with-illegal-list-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-list-module/restconf-module-with-illegal-list-module.yang
new file mode 100644
index 0000000..2d8fbb1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-illegal-list-module/restconf-module-with-illegal-list-module.yang
@@ -0,0 +1,684 @@
+module restconf-module-with-illegal-list-module {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ container modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ /** changed from list module to container module for testing purposes **/
+ container module {
+ description
+ "Each entry represents one module currently
+ supported by the server.";
+
+ leaf name {
+ type yang:yang-identifier;
+ description "The YANG module name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module revision date. An empty string is
+ used if no revision statement is present in the
+ YANG module.";
+ }
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server.";
+ }
+ leaf-list deviation {
+ type yang:yang-identifier;
+ description
+ "List of YANG deviation module names used by this
+ server to modify the conformance of the module
+ associated with this entry.";
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ } \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-container-modules/restconf-module-with-missing-container-modules.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-container-modules/restconf-module-with-missing-container-modules.yang
new file mode 100644
index 0000000..907533d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-container-modules/restconf-module-with-missing-container-modules.yang
@@ -0,0 +1,639 @@
+module restconf-module-with-missing-container-modules {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ // removed container modules for testing purposes
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ } \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-list-module/restconf-module-with-missing-list-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-list-module/restconf-module-with-missing-list-module.yang
new file mode 100644
index 0000000..6d2b4da
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing-mount-point/restconf-module-with-missing-list-module/restconf-module-with-missing-list-module.yang
@@ -0,0 +1,650 @@
+module restconf-module-with-missing-list-module {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ container modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ // removed list module for testing purposes + added list test-list
+ list test-list {
+ leaf test-leaf {
+ type string;
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ } \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-inet-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-inet-types.yang
new file mode 100644
index 0000000..de20feb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-inet-types.yang
@@ -0,0 +1,418 @@
+ module ietf-inet-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+ prefix "inet";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ typedef ip-version {
+ type enumeration {
+ enum unknown {
+ value "0";
+ description
+ "An unknown or unspecified version of the Internet protocol.";
+ }
+ enum ipv4 {
+ value "1";
+ description
+ "The IPv4 protocol as defined in RFC 791.";
+ }
+ enum ipv6 {
+ value "2";
+ description
+ "The IPv6 protocol as defined in RFC 2460.";
+ }
+ }
+ description
+ "This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.";
+ reference
+ "RFC 791: Internet Protocol
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ typedef dscp {
+ type uint8 {
+ range "0..63";
+ }
+ description
+ "The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.";
+ reference
+ "RFC 3289: Management Information Base for the Differentiated
+ Services Architecture
+ RFC 2474: Definition of the Differentiated Services Field
+ (DS Field) in the IPv4 and IPv6 Headers
+ RFC 2780: IANA Allocation Guidelines For Values In
+ the Internet Protocol and Related Headers";
+ }
+
+ typedef ipv6-flow-label {
+ type uint32 {
+ range "0..1048575";
+ }
+ description
+ "The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.";
+ reference
+ "RFC 3595: Textual Conventions for IPv6 Flow Label
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+ }
+
+ typedef port-number {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.";
+ reference
+ "RFC 768: User Datagram Protocol
+ RFC 793: Transmission Control Protocol
+ RFC 4960: Stream Control Transmission Protocol
+ RFC 4340: Datagram Congestion Control Protocol (DCCP)
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of autonomous system related types ***/
+
+ typedef as-number {
+ type uint32;
+ description
+ "The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.";
+ reference
+ "RFC 1930: Guidelines for creation, selection, and registration
+ of an Autonomous System (AS)
+ RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+ RFC 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ typedef ip-address {
+ type union {
+ type inet:ipv4-address;
+ type inet:ipv6-address;
+ }
+ description
+ "The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '(%[\p{N}\p{L}]+)?';
+ }
+ description
+ "The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format";
+ }
+
+ typedef ipv6-address {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(%[\p{N}\p{L}]+)?';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(%.+)?';
+ }
+ description
+ "The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture
+ RFC 4007: IPv6 Scoped Address Architecture
+ RFC 5952: A Recommendation for IPv6 Address Text Representation";
+ }
+
+ typedef ip-prefix {
+ type union {
+ type inet:ipv4-prefix;
+ type inet:ipv6-prefix;
+ }
+ description
+ "The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-prefix {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+ }
+ description
+ "The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.";
+ }
+
+ typedef ipv6-prefix {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(/.+)';
+ }
+ description
+ "The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** collection of domain name and URI types ***/
+
+ typedef domain-name {
+ type string {
+ pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ + '|\.';
+ length "1..253";
+ }
+ description
+ "The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492";
+ reference
+ "RFC 952: DoD Internet Host Table Specification
+ RFC 1034: Domain Names - Concepts and Facilities
+ RFC 1123: Requirements for Internet Hosts -- Application
+ and Support
+ RFC 2782: A DNS RR for specifying the location of services
+ (DNS SRV)
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ typedef host {
+ type union {
+ type inet:ip-address;
+ type inet:domain-name;
+ }
+ description
+ "The host type represents either an IP address or a DNS
+ domain name.";
+ }
+
+ typedef uri {
+ type string;
+ description
+ "The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.";
+ reference
+ "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+ Group: Uniform Resource Identifiers (URIs), URLs,
+ and Uniform Resource Names (URNs): Clarifications
+ and Recommendations
+ RFC 5017: MIB Textual Conventions for Uniform Resource
+ Identifiers (URIs)";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-restconf@2013-10-19.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-restconf@2013-10-19.yang
new file mode 100644
index 0000000..bd8273a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-restconf@2013-10-19.yang
@@ -0,0 +1,684 @@
+module ietf-restconf {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ Copyright (c) 2013 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ container modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one module currently
+ supported by the server.";
+
+ leaf name {
+ type yang:yang-identifier;
+ description "The YANG module name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module revision date. An empty string is
+ used if no revision statement is present in the
+ YANG module.";
+ }
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server.";
+ }
+ leaf-list deviation {
+ type yang:yang-identifier;
+ description
+ "List of YANG deviation module names used by this
+ server to modify the conformance of the module
+ associated with this entry.";
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ } \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-yang-library@2016-06-21.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-yang-library@2016-06-21.yang
new file mode 100644
index 0000000..bc466ee
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-yang-library@2016-06-21.yang
@@ -0,0 +1,208 @@
+module ietf-yang-library {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-library";
+ prefix "yanglib";
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import ietf-inet-types {
+ prefix inet;
+ }
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+ WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+ WG Chair: Mahesh Jethanandani
+ <mailto:mjethanandani@gmail.com>
+ Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+ description
+ "This module contains monitoring information about the YANG
+ modules and submodules that are used within a YANG-based
+ server.
+ Copyright (c) 2016 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+ This version of this YANG module is part of RFC 7895; see
+ the RFC itself for full legal notices.";
+ revision 2016-06-21 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 7895: YANG Module Library.";
+ }
+ /*
+ * Typedefs
+ */
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.";
+ }
+ /*
+ * Groupings
+ */
+ grouping module-list {
+ description
+ "The module data structure is represented as a grouping
+ so it can be reused in configuration or another monitoring
+ data structure.";
+ grouping common-leafs {
+ description
+ "Common parameters for YANG modules and submodules.";
+ leaf name {
+ type yang:yang-identifier;
+ description
+ "The YANG module or submodule name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module or submodule revision date.
+ A zero-length string is used if no revision statement
+ is present in the YANG module or submodule.";
+ }
+ }
+ grouping schema-leaf {
+ description
+ "Common schema leaf parameter for modules and submodules.";
+ leaf schema {
+ type inet:uri;
+ description
+ "Contains a URL that represents the YANG schema
+ resource for this module or submodule.
+ This leaf will only be present if there is a URL
+ available for retrieval of the schema for this entry.";
+ }
+ }
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one revision of one module
+ currently supported by the server.";
+ uses common-leafs;
+ uses schema-leaf;
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server, regardless of whether they are
+ defined in the module or any included submodule.";
+ }
+ list deviation {
+ key "name revision";
+ description
+ "List of YANG deviation module names and revisions
+ used by this server to modify the conformance of
+ the module associated with this entry. Note that
+ the same module can be used for deviations for
+ multiple modules, so the same entry MAY appear
+ within multiple 'module' entries.
+ The deviation module MUST be present in the 'module'
+ list, with the same name and revision values.
+ The 'conformance-type' value will be 'implement' for
+ the deviation module.";
+ uses common-leafs;
+ }
+ leaf conformance-type {
+ type enumeration {
+ enum implement {
+ description
+ "Indicates that the server implements one or more
+ protocol-accessible objects defined in the YANG module
+ identified in this entry. This includes deviation
+ statements defined in the module.
+ For YANG version 1.1 modules, there is at most one
+ module entry with conformance type 'implement' for a
+ particular module name, since YANG 1.1 requires that,
+ at most, one revision of a module is implemented.
+ For YANG version 1 modules, there SHOULD NOT be more
+ than one module entry for a particular module name.";
+ }
+ enum import {
+ description
+ "Indicates that the server imports reusable definitions
+ from the specified revision of the module but does
+ not implement any protocol-accessible objects from
+ this revision.
+ Multiple module entries for the same module name MAY
+ exist. This can occur if multiple modules import the
+ same module but specify different revision dates in
+ the import statements.";
+ }
+ }
+ mandatory true;
+ description
+ "Indicates the type of conformance the server is claiming
+ for the YANG module identified by this entry.";
+ }
+ list submodule {
+ key "name revision";
+ description
+ "Each entry represents one submodule within the
+ parent module.";
+ uses common-leafs;
+ uses schema-leaf;
+ }
+ }
+ }
+ /*
+ * Operational state data nodes
+ */
+ container modules-state {
+ config false;
+ description
+ "Contains YANG module monitoring information.";
+ leaf module-set-id {
+ type string;
+ mandatory true;
+ description
+ "Contains a server-specific identifier representing
+ the current set of modules and submodules. The
+ server MUST change the value of this leaf if the
+ information represented by the 'module' list instances
+ has changed.";
+ }
+ uses module-list;
+ }
+ /*
+ * Notifications
+ */
+ notification yang-library-change {
+ description
+ "Generated when the set of modules and submodules supported
+ by the server has changed.";
+ leaf module-set-id {
+ type leafref {
+ path "/yanglib:modules-state/yanglib:module-set-id";
+ }
+ mandatory true;
+ description
+ "Contains the module-set-id value representing the
+ set of modules and submodules supported at the server at
+ the time the notification is generated.";
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-yang-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-yang-types.yang
new file mode 100644
index 0000000..c3f952c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/modules/restconf-module-testing/ietf-yang-types.yang
@@ -0,0 +1,417 @@
+ module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+
+
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined by the 'identifier'
+ rule in Section 12 of RFC 6020. An identifier must
+ start with an alphabetic character or an underscore
+ followed by an arbitrary sequence of alphabetic or
+ numeric characters, underscores, hyphens, or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lowercase or uppercase character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using the
+ time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually referring
+ to the notion of local time) uses the time-offset -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence happened.
+ The specific occurrence must be defined in the description
+ of any schema node defined using this type. When the specific
+ occurrence occurred prior to the last time the associated
+ timeticks attribute was zero, then the timestamp value is
+ zero. Note that this requires all timestamp values to be
+ reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/multiple-nodes/multiple-nodes.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/multiple-nodes/multiple-nodes.yang
new file mode 100644
index 0000000..22a1dae
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/multiple-nodes/multiple-nodes.yang
@@ -0,0 +1,17 @@
+module multiple-nodes {
+ namespace "multiple:nodes";
+ prefix "mod1";
+ revision "2014-06-23";
+
+ container cont {
+ container cont1 {
+ leaf lf11 {
+ type string;
+ }
+ }
+
+ leaf lf1 {
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-container.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-container.yang
new file mode 100644
index 0000000..7efe4f7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-container.yang
@@ -0,0 +1,22 @@
+module augment-container {
+ namespace "ns:augment:container";
+ prefix "augcont";
+
+
+ import yang {prefix yng; revision-date 2013-11-26;}
+
+
+ revision "2013-11-26" {
+ }
+
+ augment "/yng:cont" {
+ container cont1 {
+ leaf lf11 {
+ type string;
+ }
+ }
+ }
+
+
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-leaf.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-leaf.yang
new file mode 100644
index 0000000..248d3bb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-leaf.yang
@@ -0,0 +1,18 @@
+module augment-leaf {
+ namespace "ns:augment:leaf";
+ prefix "auglf";
+
+
+ import yang {prefix yng; revision-date 2013-11-26;}
+
+
+ revision "2013-11-26" {
+ }
+
+ augment "/yng:cont" {
+ leaf lf2 {
+ type string;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-leaflist.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-leaflist.yang
new file mode 100644
index 0000000..1f4b937
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-leaflist.yang
@@ -0,0 +1,20 @@
+module augment-leaflist {
+ namespace "ns:augment:leaflist";
+ prefix "auglflst";
+
+
+ import yang {prefix yng; revision-date 2013-11-26;}
+
+
+ revision "2013-11-26" {
+ }
+
+ augment "/yng:cont" {
+ leaf-list lflst1 {
+ type string;
+ }
+ }
+
+
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-list.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-list.yang
new file mode 100644
index 0000000..a35a87e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/augment-list.yang
@@ -0,0 +1,22 @@
+module augment-list {
+ namespace "ns:augment:list";
+ prefix "auglst";
+
+
+ import yang {prefix yng; revision-date 2013-11-26;}
+
+
+ revision "2013-11-26" {
+ }
+
+ augment "/yng:cont" {
+ list lst1 {
+ leaf lf11 {
+ type string;
+ }
+ }
+ }
+
+
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/xml/data.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/xml/data.xml
new file mode 100644
index 0000000..fec6209
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/xml/data.xml
@@ -0,0 +1,16 @@
+<cont xmlns="ns:yang">
+ <lf1>lf1</lf1>
+ <lf2>lf2</lf2>
+ <cont1>
+ <lf11>lf11</lf11>
+ </cont1>
+ <lst1>
+ <lf11>lf1_1</lf11>
+ </lst1>
+ <lst1>
+ <lf11>lf1_2</lf11>
+ </lst1>
+ <lflst1>lflst1_1</lflst1>
+ <lflst1>lflst1_2</lflst1>
+ <lflst1>lflst1_3</lflst1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/yang.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/yang.yang
new file mode 100644
index 0000000..327280f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/augmentation/yang.yang
@@ -0,0 +1,30 @@
+module yang {
+ namespace "ns:yang";
+
+ prefix "yng";
+ revision 2013-11-26 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type string;
+ }
+ leaf lf2 {
+ type string;
+ }
+ container cont1{
+ leaf lf11 {
+ type string;
+ }
+ }
+
+ list lst1{
+ leaf lf11 {
+ type string;
+ }
+ }
+ leaf-list lflst1{
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/choice.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/choice.yang
new file mode 100644
index 0000000..22430b9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/choice.yang
@@ -0,0 +1,125 @@
+module choice-case-test {
+ namespace "choice:case:test";
+
+ prefix "chcatst";
+ revision 2013-11-27 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type string;
+ }
+
+ choice choi1 {
+ case a1 {
+ leaf lf1a {
+ type uint16;
+ }
+ choice choi1a {
+ case aa1 {
+ leaf lf1aa {
+ type string;
+ }
+ choice choi1aa {
+ case aaa1 {
+ leaf lf1aaa {
+ type string;
+ }
+ }
+ case aab1 {
+ leaf lf1aab {
+ type string;
+ }
+ }
+ }
+ }
+ case ab1 {
+ leaf lf1ab {
+ type string;
+ }
+ }
+ }
+ }
+ case b1 {
+ list lst1b {
+ leaf lf11b {
+ type string;
+ }
+ }
+ }
+ case c1 {
+ container cont1c {
+ leaf lf11c {
+ type string;
+ }
+ }
+ }
+ case d1 {
+ leaf-list lflst1d {
+ type string;
+ }
+ }
+ leaf e1 {
+ type uint32;
+ }
+ }
+
+ choice choi2 {
+ case a2 {
+ leaf lf2a {
+ type string;
+ }
+ }
+ case b2 {
+ leaf lf2b {
+ type string;
+ }
+ }
+ }
+
+ choice choi4 {
+ case a4 {
+ list lst4a {
+ choice choi4aa {
+ case aa1 {
+ leaf lf4aa {
+ type string;
+ }
+ }
+ case ab2 {
+ leaf lf4ab {
+ type int16;
+ }
+ }
+ }
+ }
+ }
+ case b4 {
+ leaf-list lflst4b {
+ type uint32;
+ }
+ }
+
+ }
+
+/* equal identifiers in various cases are illegal 7.9.2 rfc6020 */
+/*
+ choice choi3 {
+ case 3a {
+ leaf lf3a {
+ type string;
+ }
+ }
+ case 3b {
+ leaf lf3b {
+ type string;
+ }
+ }
+ }
+*/
+
+ }
+
+
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_case_defined_without_case.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_case_defined_without_case.xml
new file mode 100644
index 0000000..1d3f99f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_case_defined_without_case.xml
@@ -0,0 +1,4 @@
+<cont xmlns="choice:case:test">
+ <e1>45</e1>
+ <lf2b>lf2b val</lf2b>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_container.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_container.xml
new file mode 100644
index 0000000..146e256
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_container.xml
@@ -0,0 +1,5 @@
+<cont xmlns="choice:case:test">
+ <cont1c>
+ <lf11c>lf11c val</lf11c>
+ </cont1c>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_leaflist.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_leaflist.xml
new file mode 100644
index 0000000..f501e04
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_leaflist.xml
@@ -0,0 +1,4 @@
+<cont xmlns="choice:case:test">
+ <lflst1d>lflst1d_1 val</lflst1d>
+ <lflst1d>lflst1d_2 val</lflst1d>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_list.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_list.xml
new file mode 100644
index 0000000..6694b48
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_list.xml
@@ -0,0 +1,8 @@
+<cont xmlns="choice:case:test">
+ <lst1b>
+ <lf11b>lf11b_1 val</lf11b>
+ </lst1b>
+ <lst1b>
+ <lf11b>lf11b_2 val</lf11b>
+ </lst1b>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_more_choices_same_level.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_more_choices_same_level.xml
new file mode 100644
index 0000000..3d2742a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_more_choices_same_level.xml
@@ -0,0 +1,6 @@
+<cont xmlns="choice:case:test">
+ <cont1c>
+ <lf11c>lf11c val</lf11c>
+ </cont1c>
+ <lf2b>lf2b value</lf2b>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml
new file mode 100644
index 0000000..aa9e24c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml
@@ -0,0 +1,7 @@
+<cont xmlns="choice:case:test">
+ <cont1c>
+ <lf11c>lf11c val</lf11c>
+ </cont1c>
+ <lf2b>lf2b value</lf2b>
+ <lf2a>lf2b value</lf2a>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_no_first_case.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_no_first_case.xml
new file mode 100644
index 0000000..cc6f019
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_no_first_case.xml
@@ -0,0 +1,5 @@
+<cont xmlns="choice:case:test">
+ <lf1>lf1 val</lf1>
+ <lf1a>121</lf1a>
+ <lf1ab>lf1ab val</lf1ab>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_random_level.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_random_level.xml
new file mode 100644
index 0000000..05ca42f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_random_level.xml
@@ -0,0 +1,6 @@
+<cont xmlns="choice:case:test">
+ <lf1aa>lf1aa val</lf1aa>
+ <lf1>lf1 val</lf1>
+ <lf1a>121</lf1a>
+ <lf1aaa>lf1aaa val</lf1aaa>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_three_choices_same_level.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_three_choices_same_level.xml
new file mode 100644
index 0000000..7e54301
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_three_choices_same_level.xml
@@ -0,0 +1,13 @@
+<cont xmlns="choice:case:test">
+ <lf1aaa>lf1aaa value</lf1aaa>
+ <lf2b>lf2b value</lf2b>
+ <lst4a>
+ <lf4ab>33</lf4ab>
+ </lst4a>
+ <lst4a>
+ <lf4ab>33</lf4ab>
+ </lst4a>
+ <lst4a>
+ <lf4ab>37</lf4ab>
+ </lst4a>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_various_path_err.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_various_path_err.xml
new file mode 100644
index 0000000..5274679
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/choice/xml/data_various_path_err.xml
@@ -0,0 +1,6 @@
+<cont xmlns="choice:case:test">
+ <lf1aa>lf1aa val</lf1aa>
+ <lf1>lf1 val</lf1>
+ <lf1a>121</lf1a>
+ <lf1ab>lf1ab value</lf1ab>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/data-of-several-modules/yang/module1.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/data-of-several-modules/yang/module1.yang
new file mode 100644
index 0000000..72a82ca
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/data-of-several-modules/yang/module1.yang
@@ -0,0 +1,20 @@
+module module1 {
+ namespace "module:one";
+
+ prefix "m1";
+ revision 2014-01-17 {
+ }
+
+ container cont_m1 {
+ leaf lf1_m1 {
+ type string;
+ }
+ uses confB_gr;
+ }
+
+ grouping confB_gr {
+ container contB_m1 {
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/data-of-several-modules/yang/module2.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/data-of-several-modules/yang/module2.yang
new file mode 100644
index 0000000..521d9c0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/data-of-several-modules/yang/module2.yang
@@ -0,0 +1,20 @@
+module module2 {
+ namespace "module:two";
+
+ prefix "m2";
+ revision 2014-01-17 {
+ }
+
+ container cont_m2 {
+ leaf lf1_m2 {
+ type string;
+ }
+ uses confB_gr;
+ }
+
+ grouping confB_gr {
+ container contB_m2 {
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/identityref/identity-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/identityref/identity-module.yang
new file mode 100644
index 0000000..09a34c5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/identityref/identity-module.yang
@@ -0,0 +1,10 @@
+module identity-module {
+ namespace "identity:module";
+
+ prefix "idemod";
+ revision 2013-12-02 {
+ }
+
+ identity iden {
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/identityref/identityref-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/identityref/identityref-module.yang
new file mode 100644
index 0000000..c5c8f62
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/identityref/identityref-module.yang
@@ -0,0 +1,21 @@
+module identityref-module {
+ namespace "identityref:module";
+
+ prefix "iderefmod";
+
+ import identity-module {prefix idemo; revision-date 2013-12-02; }
+
+ revision 2013-12-02 {
+ }
+
+ container cont {
+ container cont1 {
+ leaf lf1 {
+ type identityref {
+ base "idemo:iden";
+ }
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/invalid-top-level-element/invalid-top-level-element.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/invalid-top-level-element/invalid-top-level-element.yang
new file mode 100644
index 0000000..a9df486
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/invalid-top-level-element/invalid-top-level-element.yang
@@ -0,0 +1,13 @@
+module invalid-top-level-element {
+ namespace "invalid:top:level:element";
+
+ prefix "intoleel";
+ revision 2013-12-17 {
+ }
+
+
+ leaf lf {
+ type string;
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/cont-augment-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/cont-augment-module.yang
new file mode 100644
index 0000000..b54027e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/cont-augment-module.yang
@@ -0,0 +1,39 @@
+module cont-augment-module {
+ namespace "cont:augment:module";
+
+ prefix "cntaugmod";
+
+ import main-module {prefix mamo; revision-date 2013-12-02;}
+
+ revision 2013-12-02 {
+
+ }
+
+ augment "/mamo:cont" {
+ leaf-list lflst1 {
+ type leafref {
+ path "../mamo:lf1";
+ }
+ }
+
+ leaf lf4 {
+ type leafref {
+ path "../mamo:lf1";
+ }
+ }
+
+ /* reference to not leaf element */
+ leaf lf6 {
+ type leafref {
+ path "../lflst1";
+ }
+ }
+
+ leaf lf7 {
+ type leafref {
+ path "../lf4";
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/main-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/main-module.yang
new file mode 100644
index 0000000..0d90d2b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/main-module.yang
@@ -0,0 +1,50 @@
+module main-module {
+ namespace "main:module";
+
+ prefix "mainmod";
+ revision 2013-12-02 {
+ }
+
+ container cont {
+ leaf lf1 {
+ /*
+ *FIX ME
+ * If is this leaf lf1 called from cont-augment-module.yang
+ * from lf4, type that will be returned to the lf1 is string.
+ * Than there are failing tests because of we have string,
+ * do not number(uint32)
+ */
+// type uint32;
+ type string;
+ }
+
+ container cont1 {
+ leaf lf11 {
+ /*
+ * FIX ME TOO WITH BAD PARSING
+ */
+// type boolean;
+ type string;
+ }
+ }
+
+ leaf lf2 {
+ type leafref {
+ path "../lf1";
+ }
+ }
+
+ leaf lf3 {
+ type leafref {
+ path "/cont/cont1/lf11";
+ }
+ }
+
+ /* reference to nonexisting leaf */
+ leaf lf5 {
+ type leafref {
+ path "/cont/lf";
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml
new file mode 100644
index 0000000..bd5b6a2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml
@@ -0,0 +1,7 @@
+<cont xmlns="main:module"
+ xmlns:cont-augment-module="cont:augment:module">
+ <cont1>
+ <lf11>true</lf11>
+ </cont1>
+ <lf3>true</lf3>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_from_leafref_to_leafref.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_from_leafref_to_leafref.xml
new file mode 100644
index 0000000..7b1c277
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_from_leafref_to_leafref.xml
@@ -0,0 +1,4 @@
+<cont xmlns="main:module"
+ xmlns:cont-augment-module="cont:augment:module">
+ <cont-augment-module:lf7>200</cont-augment-module:lf7>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml
new file mode 100644
index 0000000..cdbd56b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml
@@ -0,0 +1,4 @@
+<cont xmlns="main:module"
+ xmlns:cont-augment-module="cont:augment:module">
+ <lf5>137</lf5>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_ref_to_not_leaf.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_ref_to_not_leaf.xml
new file mode 100644
index 0000000..953280b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_ref_to_not_leaf.xml
@@ -0,0 +1,4 @@
+<cont xmlns="main:module"
+ xmlns:cont-augment-module="cont:augment:module">
+ <cont-augment-module:lf6>44</cont-augment-module:lf6>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml
new file mode 100644
index 0000000..8fe0ac4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml
@@ -0,0 +1,6 @@
+<cont xmlns="main:module"
+ xmlns:cont-augment-module="cont:augment:module">
+ <cont-augment-module:lflst1>345</cont-augment-module:lflst1>
+ <cont-augment-module:lflst1>346</cont-augment-module:lflst1>
+ <cont-augment-module:lflst1>347</cont-augment-module:lflst1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml
new file mode 100644
index 0000000..14a2544
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml
@@ -0,0 +1,5 @@
+<cont xmlns="main:module"
+ xmlns:cont-augment-module="cont:augment:module">
+ <lf1>121</lf1>
+ <lf2>121</lf2>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/list/list-types-module b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/list/list-types-module
new file mode 100644
index 0000000..9bdea81
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/list/list-types-module
@@ -0,0 +1,274 @@
+module simple-data-types {
+ namespace "simple:data:types";
+
+ prefix "smpdtp";
+ revision 2013-11-12 {
+ }
+
+ identity iden {
+ }
+
+ typedef tpdfempty {
+ type empty;
+ }
+
+ typedef tpdfbit {
+ type bits {
+ bit b1;
+ bit b2;
+ bit b3;
+ }
+ }
+
+ typedef tpdfun4 {
+ type boolean;
+ }
+
+ typedef tpdfun3 {
+ type union {
+ type tpdfbit;
+ type tpdfempty;
+ }
+ }
+
+ typedef tpdfun2 {
+ type union {
+ type tpdfun3;
+ type tpdfun4;
+ }
+ }
+
+ typedef tpdfun1 {
+ type union {
+ type uint8;
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+ }
+
+ container cont {
+ leaf lfnint8Min {
+ type int8;
+ }
+ leaf lfnint8Max {
+ type int8;
+ }
+ leaf lfnint16Min {
+ type int16;
+ }
+ leaf lfnint16Max {
+ type int16;
+ }
+ leaf lfnint32Min {
+ type int32;
+ }
+ leaf lfnint32Max {
+ type int32;
+ }
+ leaf lfnint64Min {
+ type int64;
+ }
+ leaf lfnint64Max {
+ type int64;
+ }
+
+ leaf lfnuint8Max {
+ type uint8;
+ }
+ leaf lfnuint16Max {
+ type uint16;
+ }
+ leaf lfnuint32Max {
+ type uint32;
+ }
+ leaf lfuint64Max {
+ type uint64;
+ }
+ leaf lfstr {
+ type string;
+ }
+ leaf lfstr1 {
+ type string;
+ }
+ leaf lfbool1 {
+ type boolean;
+ }
+ leaf lfbool2 {
+ type boolean;
+ }
+ leaf lfbool3 {
+ type boolean;
+ }
+ leaf lfdecimal1 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+ leaf lfdecimal2 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+ leaf lfdecimal3 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+ leaf lfdecimal4 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+
+ leaf lfdecimal6 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+ leaf lfenum {
+ type enumeration {
+ enum enum1;
+ enum enum2;
+ enum enum3;
+ enum enum4;
+ }
+ }
+
+ leaf lfbits {
+ type bits {
+ bit bit1;
+ bit bit2;
+ bit bit3;
+ bit bit4;
+ }
+ }
+
+ leaf lfbinary {
+ type binary;
+ }
+
+ leaf lfref1 { //reference to string type
+ type leafref {
+ path "../lfstr";
+ }
+ }
+
+ leaf lfref2 { //reference to number type
+ type leafref {
+ path "../lfnint8Max";
+ }
+ }
+
+ leaf lfempty {
+ type empty;
+ }
+
+ leaf lfunion1 {
+ type union {
+ type uint16;
+ type string;
+ }
+ }
+ leaf lfunion2 {
+ type union {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ type string;
+ }
+ }
+
+ leaf lfunion3 {
+ type union {
+ type empty;
+ type string;
+ }
+ }
+
+ leaf lfunion4 {
+ type union {
+ type boolean;
+ type string;
+ }
+ }
+
+ leaf lfunion5 {
+ type union {
+ type uint16;
+ type string;
+ }
+ }
+
+ leaf lfunion6 {
+ type union {
+ type uint16;
+ type empty;
+ }
+ }
+
+ leaf lfunion7 {
+ type tpdfun3;
+ }
+
+ leaf lfunion8 {
+ type union {
+ type uint16;
+ type string;
+ }
+ }
+
+ leaf lfunion9 {
+ type union {
+ type uint16;
+ type boolean;
+ }
+ }
+
+ leaf lfunion10 {
+ type union {
+ type bits {
+ bit bt1;
+ bit bt2;
+ }
+ type boolean;
+ }
+ }
+
+ leaf lfunion11 {
+ type union {
+ type tpdfun1;
+ type tpdfun2;
+ }
+ }
+
+ leaf lfunion12 {
+ type tpdfun2;
+ }
+
+ leaf lfunion13 {
+ type tpdfbit;
+ }
+
+ leaf lfunion14 {
+ type union {
+ type enumeration {
+ enum zero;
+ enum one;
+ }
+ type uint16;
+ }
+ }
+
+ leaf identityref1 {
+ type identityref {
+ base iden;
+ }
+ }
+
+
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/simple-data-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/simple-data-types.yang
new file mode 100644
index 0000000..cf6e513
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/simple-data-types.yang
@@ -0,0 +1,278 @@
+module simple-data-types {
+ namespace "simple:data:types";
+
+ prefix "smpdtp";
+ revision 2013-11-12 {
+ }
+
+ identity iden {
+ }
+
+ typedef tpdfempty {
+ type empty;
+ }
+
+ typedef tpdfbit {
+ type bits {
+ bit b1;
+ bit b2;
+ bit b3;
+ }
+ }
+
+ typedef tpdfun4 {
+ type boolean;
+ }
+
+ typedef tpdfun3 {
+ type union {
+ type tpdfbit;
+ type tpdfempty;
+ }
+ }
+
+ typedef tpdfun2 {
+ type union {
+ type tpdfun3;
+ type tpdfun4;
+ }
+ }
+
+ typedef tpdfun1 {
+ type union {
+ type uint8;
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+ }
+
+ container cont {
+ leaf lfnint8Min {
+ type int8;
+ }
+ leaf lfnint8Max {
+ type int8;
+ }
+ leaf lfnint16Min {
+ type int16;
+ }
+ leaf lfnint16Max {
+ type int16;
+ }
+ leaf lfnint32Min {
+ type int32;
+ }
+ leaf lfnint32Max {
+ type int32;
+ }
+ leaf lfnint64Min {
+ type int64;
+ }
+ leaf lfnint64Max {
+ type int64;
+ }
+
+ leaf lfnuint8Max {
+ type uint8;
+ }
+ leaf lfnuint16Max {
+ type uint16;
+ }
+ leaf lfnuint32Max {
+ type uint32;
+ }
+ leaf lfuint64Max {
+ type uint64;
+ }
+ leaf lfstr {
+ type string;
+ }
+ leaf lfstr1 {
+ type string;
+ }
+ leaf lfbool1 {
+ type boolean;
+ }
+ leaf lfbool2 {
+ type boolean;
+ }
+ leaf lfbool3 {
+ type boolean;
+ }
+ leaf lfdecimal1 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+ leaf lfdecimal2 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+ leaf lfdecimal3 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+ leaf lfdecimal4 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+
+ leaf lfdecimal6 {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+ leaf lfenum {
+ type enumeration {
+ enum enum1;
+ enum enum2;
+ enum enum3;
+ enum enum4;
+ }
+ }
+
+ leaf lfbits {
+ type bits {
+ bit bit1;
+ bit bit2;
+ bit bit3;
+ bit bit4;
+ }
+ }
+
+ leaf lfbinary {
+ type binary;
+ }
+
+ leaf lfref1 { //reference to string type
+ type leafref {
+ path "../lfstr";
+ }
+ }
+
+ leaf lfref2 { //reference to number type
+ type leafref {
+ path "../lfnint8Max";
+ }
+ }
+
+ leaf lfempty {
+ type empty;
+ }
+
+ leaf lfunion1 {
+ type union {
+ type uint16;
+ type string;
+ }
+ }
+ leaf lfunion2 {
+ type union {
+ type decimal64 {
+ fraction-digits 2;
+ }
+ type string;
+ }
+ }
+
+ leaf lfunion3 {
+ type union {
+ type empty;
+ type string;
+ }
+ }
+
+ leaf lfunion4 {
+ type union {
+ type boolean;
+ type string;
+ }
+ }
+
+ leaf lfunion5 {
+ type union {
+ type uint16;
+ type string;
+ }
+ }
+
+ leaf lfunion6 {
+ type union {
+ type uint16;
+ type empty;
+ }
+ }
+
+ leaf lfunion7 {
+ type tpdfun3;
+ }
+
+ leaf lfunion8 {
+ type union {
+ type uint16;
+ type string;
+ }
+ }
+
+ leaf lfunion9 {
+ type union {
+ type uint16;
+ type boolean;
+ }
+ }
+
+ leaf lfunion10 {
+ type union {
+ type bits {
+ bit bt1;
+ bit bt2;
+ }
+ type boolean;
+ }
+ }
+
+ leaf lfunion11 {
+ type union {
+ type tpdfun1;
+ type tpdfun2;
+ }
+ }
+
+ leaf lfunion12 {
+ type tpdfun2;
+ }
+
+ leaf lfunion13 {
+ type tpdfbit;
+ }
+
+ leaf lfunion14 {
+ type union {
+ type enumeration {
+ enum zero;
+ enum one;
+ }
+ type uint16;
+ }
+ }
+
+ leaf identityref1 {
+ type identityref {
+ base iden;
+ }
+ }
+
+ anyxml complex-any;
+
+ anyxml simple-any;
+
+ anyxml empty-any;
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/xml/bad-data.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/xml/bad-data.xml
new file mode 100644
index 0000000..31dfad1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/xml/bad-data.xml
@@ -0,0 +1,3 @@
+<cont xmlns= "simple:data:types">
+ <lfnint8Min>invalid</lfnint8Min>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/xml/data.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/xml/data.xml
new file mode 100644
index 0000000..86043d7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-data-types/xml/data.xml
@@ -0,0 +1,71 @@
+<cont xmlns="simple:data:types">
+ <lfnint8Min>-128</lfnint8Min>
+ <lfnint8Max>127</lfnint8Max>
+ <lfnint16Min>-32768</lfnint16Min>
+ <lfnint16Max>32767</lfnint16Max>
+ <lfnint32Min>-2147483648</lfnint32Min>
+ <lfnint32Max>2147483647</lfnint32Max>
+ <lfnint64Min>-9223372036854775808</lfnint64Min>
+ <lfnint64Max>9223372036854775807</lfnint64Max>
+ <lfnuint8Max>255</lfnuint8Max>
+ <lfnuint16Max>65535</lfnuint16Max>
+ <lfnuint32Max>4294967295</lfnuint32Max>
+ <lfstr>lfstr</lfstr>
+ <lfstr1></lfstr1>
+ <lfbool1>true</lfbool1>
+ <lfbool2>false</lfbool2>
+ <lfbool3>bla</lfbool3>
+ <lfdecimal1>43.32</lfdecimal1>
+ <lfdecimal2>-0.43</lfdecimal2>
+ <lfdecimal3>43</lfdecimal3>
+ <lfdecimal4>43E3</lfdecimal4>
+ <lfdecimal6>33.12345</lfdecimal6>
+ <lfenum>enum3</lfenum>
+ <lfbits>bit3 bit2</lfbits>
+ <lfbinary>ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz</lfbinary>
+ <lfunion1>324</lfunion1>
+ <lfunion2>33.3</lfunion2>
+ <lfunion3>55</lfunion3>
+ <lfunion4>true</lfunion4>
+ <lfunion5>true</lfunion5>
+ <lfunion6>10</lfunion6>
+ <lfunion7></lfunion7>
+ <lfunion8></lfunion8>
+ <lfunion9></lfunion9>
+ <lfunion10>bt1</lfunion10>
+ <lfunion11>33</lfunion11>
+ <lfunion12>false</lfunion12>
+ <lfunion13>b1</lfunion13>
+ <lfunion14>zero</lfunion14>
+ <lfempty></lfempty>
+ <identityref1 xmlns:x="simple:data:types">x:iden</identityref1>
+ <complex-any>
+ <data>
+ <leaf1>leaf1-value</leaf1>
+ <leaf2>leaf2-value</leaf2>
+
+ <leaf-list>leaf-list-value1</leaf-list>
+ <leaf-list>leaf-list-value2</leaf-list>
+
+ <list>
+ <nested-list>
+ <nested-leaf>nested-value1</nested-leaf>
+ </nested-list>
+ <nested-list>
+ <nested-leaf>nested-value2</nested-leaf>
+ </nested-list>
+ </list>
+
+ <list>
+ <nested-list>
+ <nested-leaf>nested-value3</nested-leaf>
+ </nested-list>
+ <nested-list>
+ <nested-leaf>nested-value4</nested-leaf>
+ </nested-list>
+ </list>
+ </data>
+ </complex-any>
+ <simple-any>simple</simple-any>
+ <empty-any></empty-any>
+</cont>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/simple-yang-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/simple-yang-types.yang
new file mode 100644
index 0000000..fdb3bfb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/simple-yang-types.yang
@@ -0,0 +1,57 @@
+module simple-yang-types {
+ namespace "simple:yang:types";
+
+ prefix "smptp";
+ revision 2013-11-5 {
+ description "Initial revision.";
+ }
+
+ container cont1 {
+ leaf lf11 {
+ type string;
+ }
+ leaf-list lflst11 {
+ type int32;
+ }
+ leaf-list lflst12 {
+ type string;
+ }
+ list lst11 {
+ key "lf111";
+ leaf lf111 {
+ type uint8;
+ }
+ leaf lf112 {
+ type string;
+ }
+ container cont111 {
+ leaf lf1111 {
+ type string;
+ }
+ leaf-list lflst1111 {
+ type int32;
+ }
+ list lst1111 {
+ leaf lf1111A {
+ type string;
+ }
+ leaf lf1111B {
+ type uint8;
+ }
+ }
+ }
+ list lst111 {
+ leaf lf1111 {
+ type int32;
+ }
+ }
+ list lst112 {
+ leaf lf1121 {
+ type string;
+ }
+ }
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/awaited_output_data.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/awaited_output_data.json
new file mode 100644
index 0000000..8888e7f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/awaited_output_data.json
@@ -0,0 +1,72 @@
+{
+ "cont1": {
+ "lf11":"lf",
+ "lflst11": [55,56,57],
+ "lflst12": ["lflst12 str1", "lflst12 str2", "lflst12 str3"],
+ "lst11": [
+ {
+ "lf111":140,
+ "lf112":"lf112 str",
+ "cont111": {
+ "lf1111":"lf1111 str",
+ "lflst1111": [2048, 1024, 4096],
+ "lst1111": [
+ {
+ "lf1111A": "lf1111A str11",
+ "lf1111B": 4
+ },
+ {
+ "lf1111A": "lf1111A str12",
+ "lf1111B": 7
+ }
+ ]
+ },
+ "lst111" : [
+ {
+ "lf1111" : 65
+ }
+ ],
+ "lst112" : [
+ {
+ "lf1121" : "lf1121 str11"
+ }
+ ]
+
+ },
+ {
+ "lf111":141,
+ "lf112":"lf112 str2",
+ "cont111": {
+ "lf1111":"lf1111 str2",
+ "lflst1111": [2049, 1025, 4097],
+ "lst1111": [
+ {
+ "lf1111A": "lf1111A str21",
+ "lf1111B": 5
+ },
+ {
+ "lf1111A": "lf1111A str22",
+ "lf1111B": 8
+ }
+ ]
+ },
+ "lst111" : [
+ {
+ "lf1111" : 55
+ },
+ {
+ "lf1111" : 56
+ }
+ ],
+ "lst112" : [
+ {
+ "lf1121" : "lf1121 str21"
+ },
+ {
+ "lf1121" : "lf1121 str22"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/awaited_output_empty_data.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/awaited_output_empty_data.json
new file mode 100644
index 0000000..4b19988
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/awaited_output_empty_data.json
@@ -0,0 +1,49 @@
+{
+ "cont1": {
+ "lst11": [
+ {
+ "lf111": 1,
+ "lst111": [
+ {
+ "lf1111": 34
+ },
+ {
+ "lf1111": 35
+ },
+ {},
+ {}
+ ],
+ "cont111": {}
+ },
+ {
+ "lf111": 2,
+ "cont111": {
+ "lflst1111": [
+ 1024,
+ 4096
+ ],
+ "lst1111": [
+ {
+ "lf1111B": 4
+ },
+ {
+ "lf1111A": "lf1111A str12"
+ }
+ ]
+ },
+ "lst112": [
+ {}
+ ]
+ },
+ {
+ "lf111": 3,
+ "cont111": {
+ "lst1111": [
+ {},
+ {}
+ ]
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/data.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/data.xml
new file mode 100644
index 0000000..1df9ca5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/data.xml
@@ -0,0 +1,63 @@
+<cont1 xmlns="simple:yang:types">
+ <lf11>lf</lf11>
+ <lflst11>56</lflst11>
+ <lflst11>55</lflst11>
+ <lflst11>57</lflst11>
+ <lflst12>lflst12 str3</lflst12>
+ <lst11>
+ <lst112>
+ <lf1121>lf1121 str22</lf1121>
+ </lst112>
+ <lf111>141</lf111>
+ <lf112>lf112 str2</lf112>
+ <lst111>
+ <lf1111>55</lf1111>
+ </lst111>
+ <cont111>
+ <lflst1111>4097</lflst1111>
+ <lflst1111>2049</lflst1111>
+ <lflst1111>1025</lflst1111>
+ <lst1111>
+ <lf1111A>lf1111A str22</lf1111A>
+ <lf1111B>8</lf1111B>
+ </lst1111>
+ <lf1111>lf1111 str2</lf1111>
+ <lst1111>
+ <lf1111B>5</lf1111B>
+ <lf1111A>lf1111A str21</lf1111A>
+ </lst1111>
+ </cont111>
+ <lst111>
+ <lf1111>56</lf1111>
+ </lst111>
+ <lst112>
+ <lf1121>lf1121 str21</lf1121>
+ </lst112>
+ </lst11>
+ <lflst12>lflst12 str1</lflst12>
+ <lst11>
+ <lf111>140</lf111>
+ <lf112>lf112 str</lf112>
+ <cont111>
+ <lf1111>lf1111 str</lf1111>
+ <lflst1111>2048</lflst1111>
+ <lflst1111>1024</lflst1111>
+ <lflst1111>4096</lflst1111>
+ <lst1111>
+ <lf1111A>lf1111A str11</lf1111A>
+ <lf1111B>4</lf1111B>
+ </lst1111>
+ <lst1111>
+ <lf1111A>lf1111A str12</lf1111A>
+ <lf1111B>7</lf1111B>
+ </lst1111>
+ </cont111>
+ <lst111>
+ <lf1111>65</lf1111>
+ </lst111>
+ <lst112>
+ <lf1121>lf1121 str11</lf1121>
+ </lst112>
+ </lst11>
+ <lflst12>lflst12 str2</lflst12>
+</cont1>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/empty_data.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/empty_data.xml
new file mode 100644
index 0000000..9cd503e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-json/simple-yang-types/xml/empty_data.xml
@@ -0,0 +1,40 @@
+<cont1>
+ <lst11>
+ <lf111>1</lf111>
+ <lst111></lst111>
+ <lst111></lst111>
+ <lst111>
+ <lf1111></lf1111>
+ </lst111>
+ <lst111>
+ <lf1111>35</lf1111>
+ </lst111>
+ <cont111></cont111>
+ </lst11>
+ <lst11>
+ <lf111>2</lf111>
+ <cont111>
+ <lf1111></lf1111>
+ <lflst1111></lflst1111>
+ <lflst1111>1024</lflst1111>
+ <lflst1111>4096</lflst1111>
+ <lst1111>
+ <lf1111B>4</lf1111B>
+ </lst1111>
+ <lst1111>
+ <lf1111A>lf1111A str12</lf1111A>
+ </lst1111>
+ </cont111>
+ <lst112></lst112>
+ </lst11>
+ <lst11>
+ <lf111>3</lf111>
+ <cont111>
+ <lf1111></lf1111>
+ <lflst1111></lflst1111>
+ <lflst1111></lflst1111>
+ <lst1111></lst1111>
+ <lst1111></lst1111>
+ </cont111>
+ </lst11>
+</cont1>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/choice/module-with-choice.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/choice/module-with-choice.yang
new file mode 100644
index 0000000..8454784
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/choice/module-with-choice.yang
@@ -0,0 +1,25 @@
+module module-with-choice {
+ namespace "module:with:choice";
+
+ prefix "mowicho";
+
+ revision 2013-12-18 {
+ }
+
+
+ container cont {
+ choice choA {
+ case caA1 {
+ leaf lf1 {
+ type string;
+ }
+ }
+ case caA2 {
+ leaf lf2 {
+ type string;
+ }
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/data-of-several-modules/yang/module1.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/data-of-several-modules/yang/module1.yang
new file mode 100644
index 0000000..72a82ca
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/data-of-several-modules/yang/module1.yang
@@ -0,0 +1,20 @@
+module module1 {
+ namespace "module:one";
+
+ prefix "m1";
+ revision 2014-01-17 {
+ }
+
+ container cont_m1 {
+ leaf lf1_m1 {
+ type string;
+ }
+ uses confB_gr;
+ }
+
+ grouping confB_gr {
+ container contB_m1 {
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/data-of-several-modules/yang/module2.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/data-of-several-modules/yang/module2.yang
new file mode 100644
index 0000000..521d9c0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/data-of-several-modules/yang/module2.yang
@@ -0,0 +1,20 @@
+module module2 {
+ namespace "module:two";
+
+ prefix "m2";
+ revision 2014-01-17 {
+ }
+
+ container cont_m2 {
+ leaf lf1_m2 {
+ type string;
+ }
+ uses confB_gr;
+ }
+
+ grouping confB_gr {
+ container contB_m2 {
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/aug-referenced-elements-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/aug-referenced-elements-module.yang
new file mode 100644
index 0000000..5829e04
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/aug-referenced-elements-module.yang
@@ -0,0 +1,18 @@
+module aug-referenced-elements-module {
+ namespace "aug:referenced:elements:module";
+
+ prefix "augrefelmo";
+
+ import referenced-elements-module {prefix refelmo; revision-date 2013-12-03;}
+
+ revision 2013-12-03 {
+ }
+
+ augment "/refelmo:cont" {
+ leaf lf2 {
+ type boolean;
+ }
+ }
+
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/eferenced-elements-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/eferenced-elements-module.yang
new file mode 100644
index 0000000..a844ac6
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/eferenced-elements-module.yang
@@ -0,0 +1,20 @@
+module referenced-elements-module {
+ namespace "referenced:elements:module";
+
+ prefix "refelmo";
+
+ revision 2013-12-03 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type string;
+ }
+ }
+ leaf-list lflst1 {
+ type uint32;
+ }
+
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/rinstance-identifier-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/rinstance-identifier-module.yang
new file mode 100644
index 0000000..41a9001
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/instance_identifier/rinstance-identifier-module.yang
@@ -0,0 +1,16 @@
+module instance-identifier-module {
+ namespace "instance:identifier:module";
+
+ prefix "inidmod";
+
+ revision 2013-12-03 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type instance-identifier {
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/yang/basic-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/yang/basic-module.yang
new file mode 100644
index 0000000..efbac4d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/yang/basic-module.yang
@@ -0,0 +1,111 @@
+module basic-module {
+ namespace "basic:module";
+
+ prefix "basmod";
+
+ import referenced-module {prefix refmo; revision-date 2013-12-02;}
+
+ revision 2013-12-02 {
+ }
+
+ container cont {
+ container cont1 {
+ leaf lf11 {
+ type identityref {
+ base "refmo:iden";
+ }
+ }
+ }
+ leaf lfStr {
+ type string;
+ }
+ leaf lfInt8 {
+ type int8;
+ }
+
+ leaf lfInt16 {
+ type int16;
+ }
+
+ leaf lfInt32 {
+ type int32;
+ }
+
+ leaf lfInt64 {
+ type int64;
+ }
+
+ leaf lfUint8 {
+ type uint8;
+ }
+
+ leaf lfUint16 {
+ type uint16;
+ }
+
+ leaf lfUint32 {
+ type uint32;
+ }
+
+ leaf lfUint64 {
+ type uint64;
+ }
+
+ leaf lfBinary {
+ type binary;
+ }
+
+ leaf lfBits {
+ type bits {
+ bit one;
+ bit two;
+ bit three;
+ }
+ }
+
+ leaf lfEnumeration {
+ type enumeration {
+ enum enum1;
+ enum enum2;
+ enum enum3;
+ }
+ }
+
+ leaf lfEmpty {
+ type empty;
+ }
+
+ leaf lfBoolean {
+ type boolean;
+ }
+
+ leaf lfUnion {
+ type union {
+ type int8;
+ type string;
+ type bits {
+ bit first;
+ bit second;
+ }
+ type boolean;
+ }
+ }
+
+ leaf lfLfref {
+ type leafref {
+ path "/cont/lfBoolean";
+ }
+ }
+
+ leaf lfLfrefNegative {
+ type leafref {
+ path "/cont/not-existing";
+ }
+ }
+
+ leaf lfInIdentifier {
+ type instance-identifier;
+ }
+
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/yang/referenced-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/yang/referenced-module.yang
new file mode 100644
index 0000000..e78266f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/nn-to-xml/yang/referenced-module.yang
@@ -0,0 +1,10 @@
+module referenced-module {
+ namespace "referenced:module";
+
+ prefix "refmod";
+ revision 2013-12-02 {
+ }
+
+ identity iden {
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/normalize-node/yang/normalize-node-module b/netconf/restconf/restconf-nb-bierman02/src/test/resources/normalize-node/yang/normalize-node-module
new file mode 100644
index 0000000..15e68ef
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/normalize-node/yang/normalize-node-module
@@ -0,0 +1,14 @@
+module normalize-node-module {
+ namespace "normalize:node:module";
+
+ prefix "nonomo";
+ revision 2014-01-09 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type int32;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-inet-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-inet-types.yang
new file mode 100644
index 0000000..de20feb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-inet-types.yang
@@ -0,0 +1,418 @@
+ module ietf-inet-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+ prefix "inet";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ typedef ip-version {
+ type enumeration {
+ enum unknown {
+ value "0";
+ description
+ "An unknown or unspecified version of the Internet protocol.";
+ }
+ enum ipv4 {
+ value "1";
+ description
+ "The IPv4 protocol as defined in RFC 791.";
+ }
+ enum ipv6 {
+ value "2";
+ description
+ "The IPv6 protocol as defined in RFC 2460.";
+ }
+ }
+ description
+ "This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.";
+ reference
+ "RFC 791: Internet Protocol
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ typedef dscp {
+ type uint8 {
+ range "0..63";
+ }
+ description
+ "The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.";
+ reference
+ "RFC 3289: Management Information Base for the Differentiated
+ Services Architecture
+ RFC 2474: Definition of the Differentiated Services Field
+ (DS Field) in the IPv4 and IPv6 Headers
+ RFC 2780: IANA Allocation Guidelines For Values In
+ the Internet Protocol and Related Headers";
+ }
+
+ typedef ipv6-flow-label {
+ type uint32 {
+ range "0..1048575";
+ }
+ description
+ "The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.";
+ reference
+ "RFC 3595: Textual Conventions for IPv6 Flow Label
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+ }
+
+ typedef port-number {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.";
+ reference
+ "RFC 768: User Datagram Protocol
+ RFC 793: Transmission Control Protocol
+ RFC 4960: Stream Control Transmission Protocol
+ RFC 4340: Datagram Congestion Control Protocol (DCCP)
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of autonomous system related types ***/
+
+ typedef as-number {
+ type uint32;
+ description
+ "The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.";
+ reference
+ "RFC 1930: Guidelines for creation, selection, and registration
+ of an Autonomous System (AS)
+ RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+ RFC 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ typedef ip-address {
+ type union {
+ type inet:ipv4-address;
+ type inet:ipv6-address;
+ }
+ description
+ "The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '(%[\p{N}\p{L}]+)?';
+ }
+ description
+ "The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format";
+ }
+
+ typedef ipv6-address {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(%[\p{N}\p{L}]+)?';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(%.+)?';
+ }
+ description
+ "The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture
+ RFC 4007: IPv6 Scoped Address Architecture
+ RFC 5952: A Recommendation for IPv6 Address Text Representation";
+ }
+
+ typedef ip-prefix {
+ type union {
+ type inet:ipv4-prefix;
+ type inet:ipv6-prefix;
+ }
+ description
+ "The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-prefix {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+ }
+ description
+ "The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.";
+ }
+
+ typedef ipv6-prefix {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(/.+)';
+ }
+ description
+ "The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** collection of domain name and URI types ***/
+
+ typedef domain-name {
+ type string {
+ pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ + '|\.';
+ length "1..253";
+ }
+ description
+ "The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492";
+ reference
+ "RFC 952: DoD Internet Host Table Specification
+ RFC 1034: Domain Names - Concepts and Facilities
+ RFC 1123: Requirements for Internet Hosts -- Application
+ and Support
+ RFC 2782: A DNS RR for specifying the location of services
+ (DNS SRV)
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ typedef host {
+ type union {
+ type inet:ip-address;
+ type inet:domain-name;
+ }
+ description
+ "The host type represents either an IP address or a DNS
+ domain name.";
+ }
+
+ typedef uri {
+ type string;
+ description
+ "The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.";
+ reference
+ "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+ Group: Uniform Resource Identifiers (URIs), URLs,
+ and Uniform Resource Names (URNs): Clarifications
+ and Recommendations
+ RFC 5017: MIB Textual Conventions for Uniform Resource
+ Identifiers (URIs)";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-restconf-monitoring@2017-01-26.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-restconf-monitoring@2017-01-26.yang
new file mode 100644
index 0000000..55c3cb1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-restconf-monitoring@2017-01-26.yang
@@ -0,0 +1,149 @@
+module ietf-restconf-monitoring {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring";
+ prefix "rcmon";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ Author: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Author: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Author: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+
+ description
+ "This module contains monitoring information for the
+ RESTCONF protocol.
+
+ Copyright (c) 2017 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 8040; see
+ the RFC itself for full legal notices.";
+
+ revision 2017-01-26 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 8040: RESTCONF Protocol.";
+ }
+
+ container restconf-state {
+ config false;
+ description
+ "Contains RESTCONF protocol monitoring information.";
+
+ container capabilities {
+ description
+ "Contains a list of protocol capability URIs.";
+
+ leaf-list capability {
+ type inet:uri;
+ description
+ "A RESTCONF protocol capability URI.";
+ }
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description
+ "The stream name.";
+ reference
+ "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "Description of stream content.";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ default false;
+ description
+ "Indicates if replay buffer is supported for this stream.
+ If 'true', then the server MUST support the 'start-time'
+ and 'stop-time' query parameters for this stream.";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ when "../replay-support" {
+ description
+ "Only present if notification replay is supported.";
+ }
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ list access {
+ key encoding;
+ min-elements 1;
+ description
+ "The server will create an entry in this list for each
+ encoding format that is supported for this stream.
+ The media type 'text/event-stream' is expected
+ for all event streams. This list identifies the
+ subtypes supported for this stream.";
+
+ leaf encoding {
+ type string;
+ description
+ "This is the secondary encoding format within the
+ 'text/event-stream' encoding used by all streams.
+ The type 'xml' is supported for XML encoding.
+ The type 'json' is supported for JSON encoding.";
+ }
+
+ leaf location {
+ type inet:uri;
+ mandatory true;
+ description
+ "Contains a URL that represents the entry point
+ for establishing notification delivery via
+ server-sent events.";
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-yang-library@2016-06-21.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-yang-library@2016-06-21.yang
new file mode 100644
index 0000000..bc466ee
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-yang-library@2016-06-21.yang
@@ -0,0 +1,208 @@
+module ietf-yang-library {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-library";
+ prefix "yanglib";
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import ietf-inet-types {
+ prefix inet;
+ }
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+ WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+ WG Chair: Mahesh Jethanandani
+ <mailto:mjethanandani@gmail.com>
+ Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+ description
+ "This module contains monitoring information about the YANG
+ modules and submodules that are used within a YANG-based
+ server.
+ Copyright (c) 2016 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+ This version of this YANG module is part of RFC 7895; see
+ the RFC itself for full legal notices.";
+ revision 2016-06-21 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 7895: YANG Module Library.";
+ }
+ /*
+ * Typedefs
+ */
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.";
+ }
+ /*
+ * Groupings
+ */
+ grouping module-list {
+ description
+ "The module data structure is represented as a grouping
+ so it can be reused in configuration or another monitoring
+ data structure.";
+ grouping common-leafs {
+ description
+ "Common parameters for YANG modules and submodules.";
+ leaf name {
+ type yang:yang-identifier;
+ description
+ "The YANG module or submodule name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module or submodule revision date.
+ A zero-length string is used if no revision statement
+ is present in the YANG module or submodule.";
+ }
+ }
+ grouping schema-leaf {
+ description
+ "Common schema leaf parameter for modules and submodules.";
+ leaf schema {
+ type inet:uri;
+ description
+ "Contains a URL that represents the YANG schema
+ resource for this module or submodule.
+ This leaf will only be present if there is a URL
+ available for retrieval of the schema for this entry.";
+ }
+ }
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one revision of one module
+ currently supported by the server.";
+ uses common-leafs;
+ uses schema-leaf;
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server, regardless of whether they are
+ defined in the module or any included submodule.";
+ }
+ list deviation {
+ key "name revision";
+ description
+ "List of YANG deviation module names and revisions
+ used by this server to modify the conformance of
+ the module associated with this entry. Note that
+ the same module can be used for deviations for
+ multiple modules, so the same entry MAY appear
+ within multiple 'module' entries.
+ The deviation module MUST be present in the 'module'
+ list, with the same name and revision values.
+ The 'conformance-type' value will be 'implement' for
+ the deviation module.";
+ uses common-leafs;
+ }
+ leaf conformance-type {
+ type enumeration {
+ enum implement {
+ description
+ "Indicates that the server implements one or more
+ protocol-accessible objects defined in the YANG module
+ identified in this entry. This includes deviation
+ statements defined in the module.
+ For YANG version 1.1 modules, there is at most one
+ module entry with conformance type 'implement' for a
+ particular module name, since YANG 1.1 requires that,
+ at most, one revision of a module is implemented.
+ For YANG version 1 modules, there SHOULD NOT be more
+ than one module entry for a particular module name.";
+ }
+ enum import {
+ description
+ "Indicates that the server imports reusable definitions
+ from the specified revision of the module but does
+ not implement any protocol-accessible objects from
+ this revision.
+ Multiple module entries for the same module name MAY
+ exist. This can occur if multiple modules import the
+ same module but specify different revision dates in
+ the import statements.";
+ }
+ }
+ mandatory true;
+ description
+ "Indicates the type of conformance the server is claiming
+ for the YANG module identified by this entry.";
+ }
+ list submodule {
+ key "name revision";
+ description
+ "Each entry represents one submodule within the
+ parent module.";
+ uses common-leafs;
+ uses schema-leaf;
+ }
+ }
+ }
+ /*
+ * Operational state data nodes
+ */
+ container modules-state {
+ config false;
+ description
+ "Contains YANG module monitoring information.";
+ leaf module-set-id {
+ type string;
+ mandatory true;
+ description
+ "Contains a server-specific identifier representing
+ the current set of modules and submodules. The
+ server MUST change the value of this leaf if the
+ information represented by the 'module' list instances
+ has changed.";
+ }
+ uses module-list;
+ }
+ /*
+ * Notifications
+ */
+ notification yang-library-change {
+ description
+ "Generated when the set of modules and submodules supported
+ by the server has changed.";
+ leaf module-set-id {
+ type leafref {
+ path "/yanglib:modules-state/yanglib:module-set-id";
+ }
+ mandatory true;
+ description
+ "Contains the module-set-id value representing the
+ set of modules and submodules supported at the server at
+ the time the notification is generated.";
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-yang-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-yang-types.yang
new file mode 100644
index 0000000..c3f952c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/ietf-yang-types.yang
@@ -0,0 +1,417 @@
+ module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+
+
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined by the 'identifier'
+ rule in Section 12 of RFC 6020. An identifier must
+ start with an alphabetic character or an underscore
+ followed by an arbitrary sequence of alphabetic or
+ numeric characters, underscores, hyphens, or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lowercase or uppercase character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using the
+ time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually referring
+ to the notion of local time) uses the time-offset -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence happened.
+ The specific occurrence must be defined in the description
+ of any schema node defined using this type. When the specific
+ occurrence occurred prior to the last time the associated
+ timeticks attribute was zero, then the timestamp value is
+ zero. Note that this requires all timestamp values to be
+ reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/notifi-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/notifi-module.yang
new file mode 100644
index 0000000..e9c0e4b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/notifi-module.yang
@@ -0,0 +1,49 @@
+module notifi-module {
+ namespace "notifi:mod";
+ prefix notm;
+
+ revision "2016-11-23" {
+ }
+
+ notification notifi-leaf {
+ leaf lf {
+ type string;
+ }
+ }
+
+ notification notifi-cont {
+ container cont {
+ leaf lf {
+ type string;
+ }
+ }
+ }
+
+ notification notifi-list {
+ list lst {
+ key lf;
+ leaf lf {
+ type string;
+ }
+ }
+ }
+
+ notification notifi-grp {
+ uses grp;
+ }
+
+ grouping grp {
+ leaf lf {
+ type string;
+ }
+ }
+
+ notification notifi-augm {
+ }
+
+ augment /notifi-augm {
+ leaf lf-augm {
+ type string;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/subscribe-to-notification.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/subscribe-to-notification.yang
new file mode 100644
index 0000000..5fe7df7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/subscribe-to-notification.yang
@@ -0,0 +1,18 @@
+module subscribe-to-notification {
+
+ yang-version 1;
+ namespace "subscribe:to:notification";
+ prefix "subs-to-notifi";
+
+ description
+ "Added input parameters to rpc create-data-change-event-subscription and to create-notification-stream";
+
+ revision "2016-10-28" {
+ }
+
+ container "notifi"{
+ leaf "location"{
+ type string;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/toaster.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/toaster.yang
new file mode 100644
index 0000000..da68016
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/toaster.yang
@@ -0,0 +1,200 @@
+module toaster {
+
+ yang-version 1;
+
+ namespace
+ "http://netconfcentral.org/ns/toaster";
+
+ prefix toast;
+
+ organization "Netconf Central";
+
+ contact
+ "Andy Bierman <andy@netconfcentral.org>";
+
+ description
+ "YANG version of the TOASTER-MIB.";
+
+ revision "2009-11-20" {
+ description
+ "Toaster module in progress.";
+ }
+
+
+ identity toast-type {
+ description
+ "Base for all bread types supported by the toaster.
+ New bread types not listed here nay be added in the
+ future.";
+ }
+
+ identity white-bread {
+ base toast:toast-type;
+ description "White bread.";
+ }
+
+ identity wheat-bread {
+ base toast-type;
+ description "Wheat bread.";
+ }
+
+ identity wonder-bread {
+ base toast-type;
+ description "Wonder bread.";
+ }
+
+ identity frozen-waffle {
+ base toast-type;
+ description "Frozen waffle.";
+ }
+
+ identity frozen-bagel {
+ base toast-type;
+ description "Frozen bagel.";
+ }
+
+ identity hash-brown {
+ base toast-type;
+ description "Hash browned potatos.";
+ }
+
+ typedef DisplayString {
+ type string {
+ length "0 .. 255";
+ }
+ description
+ "YANG version of the SMIv2 DisplayString TEXTUAL-CONVENTION.";
+ reference
+ "RFC 2579, section 2.";
+
+ }
+
+ container toaster {
+ presence
+ "Indicates the toaster service is available";
+ description
+ "Top-level container for all toaster database objects.";
+ leaf toasterManufacturer {
+ type DisplayString;
+ config false;
+ mandatory true;
+ description
+ "The name of the toaster's manufacturer. For instance,
+ Microsoft Toaster.";
+ }
+
+ leaf toasterModelNumber {
+ type DisplayString;
+ config false;
+ mandatory true;
+ description
+ "The name of the toaster's model. For instance,
+ Radiant Automatic.";
+ }
+
+ leaf toasterStatus {
+ type enumeration {
+ enum "up" {
+ value 1;
+ description
+ "The toaster knob position is up.
+ No toast is being made now.";
+ }
+ enum "down" {
+ value 2;
+ description
+ "The toaster knob position is down.
+ Toast is being made now.";
+ }
+ }
+ config false;
+ mandatory true;
+ description
+ "This variable indicates the current state of
+ the toaster.";
+ }
+
+ leaf darknessFactor {
+ type uint32;
+ config true;
+ default 1000;
+ description
+ "The darkness factor. Basically, the number of ms to multiple the doneness value by.";
+ }
+ } // container toaster
+
+ rpc make-toast {
+ description
+ "Make some toast.
+ The toastDone notification will be sent when
+ the toast is finished.
+ An 'in-use' error will be returned if toast
+ is already being made.
+ A 'resource-denied' error will be returned
+ if the toaster service is disabled.";
+ input {
+ leaf toasterDoneness {
+ type uint32 {
+ range "1 .. 10";
+ }
+ default '5';
+ description
+ "This variable controls how well-done is the
+ ensuing toast. It should be on a scale of 1 to 10.
+ Toast made at 10 generally is considered unfit
+ for human consumption; toast made at 1 is warmed
+ lightly.";
+ }
+
+ leaf toasterToastType {
+ type identityref {
+ base toast:toast-type;
+ }
+ default 'wheat-bread';
+ description
+ "This variable informs the toaster of the type of
+ material that is being toasted. The toaster
+ uses this information, combined with
+ toasterDoneness, to compute for how
+ long the material must be toasted to achieve
+ the required doneness.";
+ }
+ }
+ } // rpc make-toast
+
+ rpc cancel-toast {
+ description
+ "Stop making toast, if any is being made.
+ A 'resource-denied' error will be returned
+ if the toaster service is disabled.";
+ } // rpc cancel-toast
+
+ rpc restock-toaster {
+ description
+ "Restocks the toaster with the amount of bread specified.";
+
+ input {
+ leaf amountOfBreadToStock {
+ type uint32;
+ description
+ "Indicates the amount of bread to re-stock";
+ }
+ }
+ }
+
+ notification toasterOutOfBread {
+ description
+ "Indicates that the toaster has run of out bread.";
+ } // notification toasterOutOfStock
+
+ notification toasterRestocked {
+ description
+ "Indicates that the toaster has run of out bread.";
+ leaf amountOfBread {
+ type uint32;
+ description
+ "Indicates the amount of bread that was re-stocked";
+ }
+ } // notification toasterOutOfStock
+
+ } // module toaster \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/xml/output/data_change_notification_toaster_status_DOWN.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/xml/output/data_change_notification_toaster_status_DOWN.xml
new file mode 100644
index 0000000..43babd2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/xml/output/data_change_notification_toaster_status_DOWN.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
+ <eventTime>2016-11-10T04:45:31+01:00</eventTime>
+ <data-changed-notification xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote">
+ <data-change-event>
+ <path>/toaster:toaster/toaster:toasterStatus</path>
+ <operation>updated</operation>
+ <data>
+ <toasterStatus xmlns="http://netconfcentral.org/ns/toaster">down</toasterStatus>
+ </data>
+ </data-change-event>
+ </data-changed-notification>
+</notification> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/xml/output/data_change_notification_toaster_status_NUMBER.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/xml/output/data_change_notification_toaster_status_NUMBER.xml
new file mode 100644
index 0000000..8a4a866
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/notifications/xml/output/data_change_notification_toaster_status_NUMBER.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
+ <eventTime>2016-11-10T04:45:31+01:00</eventTime>
+ <data-changed-notification xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote">
+ <data-change-event>
+ <path>/toaster:toaster/toaster:toasterStatus</path>
+ <operation>updated</operation>
+ <data>
+ <toasterStatus xmlns="http://netconfcentral.org/ns/toaster">1</toasterStatus>
+ </data>
+ </data-change-event>
+ </data-changed-notification>
+</notification> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/ordered/by/user/ordered-by-user-example.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/ordered/by/user/ordered-by-user-example.yang
new file mode 100644
index 0000000..2684336
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/ordered/by/user/ordered-by-user-example.yang
@@ -0,0 +1,44 @@
+module ordered-example {
+ namespace "ordered:example";
+ prefix "oex";
+
+ revision 2016-11-13 {
+ description
+ "Initial revision.";
+ }
+
+ container cont {
+ list playlist {
+ key name;
+
+ leaf name {
+ type string;
+ }
+ list song {
+ key index;
+ ordered-by user;
+
+ leaf index {
+ type uint32;
+ }
+ leaf id {
+ type instance-identifier;
+ mandatory true;
+ description
+ "Song identifier. Must identify an instance of
+ /songs-cont/songs/song-name.";
+ }
+ }
+ }
+ }
+
+ container songs-cont{
+ list songs{
+ key song-name;
+
+ leaf song-name{
+ type string;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/invoke-rpc-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/invoke-rpc-module.yang
new file mode 100644
index 0000000..7a8bcff
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/invoke-rpc-module.yang
@@ -0,0 +1,26 @@
+module invoke-rpc-module {
+ namespace "invoke:rpc:module";
+ prefix "inrpcmod";
+ yang-version 1;
+
+ revision 2017-05-23 {
+ description "Initial revision.";
+ }
+
+ rpc rpc-test {
+ input {
+ container cont {
+ leaf lf {
+ type string;
+ }
+ }
+ }
+ output {
+ container cont-out {
+ leaf lf-out {
+ type string;
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/mount-point.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/mount-point.yang
new file mode 100644
index 0000000..02a468f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/mount-point.yang
@@ -0,0 +1,17 @@
+module mount-point {
+ namespace "mount:point";
+ prefix "mountp";
+ yang-version 1;
+
+ import parser-identifier-included { prefix pii; revision-date 2016-06-02; }
+
+ revision 2016-06-02 {
+ description "Initial revision.";
+ }
+
+ container mount-container {
+ leaf point-number {
+ type uint8;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/parser-identifier-test-included.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/parser-identifier-test-included.yang
new file mode 100644
index 0000000..d5200a9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/parser-identifier-test-included.yang
@@ -0,0 +1,23 @@
+module parser-identifier-included {
+ namespace "parser:identifier:included";
+ prefix "parseridinc";
+ yang-version 1;
+
+ revision 2016-06-02 {
+ description
+ "Initial revision.";
+ }
+
+ list list-1 {
+ key "name revision";
+ description "List in grouping";
+
+ leaf name {
+ type string;
+ }
+
+ leaf revision {
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/parser-identifier-test.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/parser-identifier-test.yang
new file mode 100644
index 0000000..ac91dc1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/parser-identifier-test.yang
@@ -0,0 +1,40 @@
+module parser-identifier {
+ namespace "parser:identifier";
+ prefix "parserid";
+ yang-version 1;
+
+ import parser-identifier-included { prefix pii; revision-date 2016-06-02; }
+
+ revision 2016-06-02 {
+ description
+ "Initial revision.";
+ }
+
+ container cont1 {
+ container cont2 {
+ list listTest {
+ uses group;
+ }
+ }
+ }
+
+ grouping group {
+ list list-in-grouping {
+ key name;
+
+ leaf name {
+ type string;
+ }
+
+ leaf leaf-A.B {
+ type uint8;
+ }
+ }
+ }
+
+ augment "/pii:list-1" {
+ leaf augment-leaf {
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/test-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/test-module.yang
new file mode 100644
index 0000000..a9a6756
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parser-identifier/test-module.yang
@@ -0,0 +1,9 @@
+module test-module {
+ namespace "test:module";
+ prefix "testm";
+ yang-version 1;
+
+ revision 2016-06-02 {
+ description "Initial revision.";
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces.json
new file mode 100644
index 0000000..0b39dc7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces.json
@@ -0,0 +1,10 @@
+{
+ "interface":[
+ {
+ "name":"eth0",
+ "type":"ethernetCsmacd",
+ "enabled":false,
+ "description": "some interface"
+ }
+ ]
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces.xml
new file mode 100644
index 0000000..19569b5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces.xml
@@ -0,0 +1,6 @@
+<interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+ <description>some interface</description>
+</interface>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces2.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces2.xml
new file mode 100644
index 0000000..b4bdec8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces2.xml
@@ -0,0 +1,5 @@
+<class xmlns="test:module">
+ <name>xxx</name>
+ <address>bbb</address>
+ <email>ccc</email>
+</class> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.json
new file mode 100644
index 0000000..7de7fac
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.json
@@ -0,0 +1,12 @@
+{
+ "ietf-interfaces:interfaces":{
+ "interface":[
+ {
+ "name":"eth0",
+ "type":"ethernetCsmacd",
+ "enabled":false,
+ "description": "some interface"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.xml
new file mode 100644
index 0000000..313f32d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.xml
@@ -0,0 +1,8 @@
+<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces" >
+ <interface>
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+ <description>some interface</description>
+ </interface>
+</interfaces> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path2.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path2.xml
new file mode 100644
index 0000000..77cb026
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path2.xml
@@ -0,0 +1,7 @@
+
+<interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+ <description>some interface</description>
+</interface>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_interface_absolute_path.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_interface_absolute_path.xml
new file mode 100644
index 0000000..19569b5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_interface_absolute_path.xml
@@ -0,0 +1,6 @@
+<interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+ <description>some interface</description>
+</interface>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_patch.json b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_patch.json
new file mode 100644
index 0000000..26b8f8d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/parts/ietf-interfaces_interfaces_patch.json
@@ -0,0 +1,22 @@
+{
+ "ietf-restconf:yang-patch" : {
+ "patch-id" : "0",
+ "edit" : [
+ {
+ "edit-id" : "edit1",
+ "operation" : "create",
+ "target" : "",
+ "value" : {
+ "interface":[
+ {
+ "name":"eth0",
+ "type":"ethernetCsmacd",
+ "enabled":"false",
+ "description": "some interface"
+ }
+ ]
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-inet-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-inet-types.yang
new file mode 100644
index 0000000..de20feb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-inet-types.yang
@@ -0,0 +1,418 @@
+ module ietf-inet-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+ prefix "inet";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types for Internet addresses and related things.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ typedef ip-version {
+ type enumeration {
+ enum unknown {
+ value "0";
+ description
+ "An unknown or unspecified version of the Internet protocol.";
+ }
+ enum ipv4 {
+ value "1";
+ description
+ "The IPv4 protocol as defined in RFC 791.";
+ }
+ enum ipv6 {
+ value "2";
+ description
+ "The IPv6 protocol as defined in RFC 2460.";
+ }
+ }
+ description
+ "This value represents the version of the IP protocol.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetVersion textual convention of the SMIv2.";
+ reference
+ "RFC 791: Internet Protocol
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ typedef dscp {
+ type uint8 {
+ range "0..63";
+ }
+ description
+ "The dscp type represents a Differentiated Services Code-Point
+ that may be used for marking packets in a traffic stream.
+
+ In the value set and its semantics, this type is equivalent
+ to the Dscp textual convention of the SMIv2.";
+ reference
+ "RFC 3289: Management Information Base for the Differentiated
+ Services Architecture
+ RFC 2474: Definition of the Differentiated Services Field
+ (DS Field) in the IPv4 and IPv6 Headers
+ RFC 2780: IANA Allocation Guidelines For Values In
+ the Internet Protocol and Related Headers";
+ }
+
+ typedef ipv6-flow-label {
+ type uint32 {
+ range "0..1048575";
+ }
+ description
+ "The flow-label type represents flow identifier or Flow Label
+ in an IPv6 packet header that may be used to discriminate
+ traffic flows.
+
+ In the value set and its semantics, this type is equivalent
+ to the IPv6FlowLabel textual convention of the SMIv2.";
+ reference
+ "RFC 3595: Textual Conventions for IPv6 Flow Label
+ RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+ }
+
+ typedef port-number {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "The port-number type represents a 16-bit port number of an
+ Internet transport layer protocol such as UDP, TCP, DCCP, or
+ SCTP. Port numbers are assigned by IANA. A current list of
+ all assignments is available from <http://www.iana.org/>.
+
+ Note that the port number value zero is reserved by IANA. In
+ situations where the value zero does not make sense, it can
+ be excluded by subtyping the port-number type.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetPortNumber textual convention of the SMIv2.";
+ reference
+ "RFC 768: User Datagram Protocol
+ RFC 793: Transmission Control Protocol
+ RFC 4960: Stream Control Transmission Protocol
+ RFC 4340: Datagram Congestion Control Protocol (DCCP)
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of autonomous system related types ***/
+
+ typedef as-number {
+ type uint32;
+ description
+ "The as-number type represents autonomous system numbers
+ which identify an Autonomous System (AS). An AS is a set
+ of routers under a single technical administration, using
+ an interior gateway protocol and common metrics to route
+ packets within the AS, and using an exterior gateway
+ protocol to route packets to other ASs'. IANA maintains
+ the AS number space and has delegated large parts to the
+ regional registries.
+
+ Autonomous system numbers were originally limited to 16
+ bits. BGP extensions have enlarged the autonomous system
+ number space to 32 bits. This type therefore uses an uint32
+ base type without a range restriction in order to support
+ a larger autonomous system number space.
+
+ In the value set and its semantics, this type is equivalent
+ to the InetAutonomousSystemNumber textual convention of
+ the SMIv2.";
+ reference
+ "RFC 1930: Guidelines for creation, selection, and registration
+ of an Autonomous System (AS)
+ RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+ RFC 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ typedef ip-address {
+ type union {
+ type inet:ipv4-address;
+ type inet:ipv6-address;
+ }
+ description
+ "The ip-address type represents an IP address and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-address {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '(%[\p{N}\p{L}]+)?';
+ }
+ description
+ "The ipv4-address type represents an IPv4 address in
+ dotted-quad notation. The IPv4 address may include a zone
+ index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format for the zone index is the numerical
+ format";
+ }
+
+ typedef ipv6-address {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(%[\p{N}\p{L}]+)?';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(%.+)?';
+ }
+ description
+ "The ipv6-address type represents an IPv6 address in full,
+ mixed, shortened, and shortened-mixed notation. The IPv6
+ address may include a zone index, separated by a % sign.
+
+ The zone index is used to disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index number or the name of an
+ interface. If the zone index is not present, the default
+ zone of the device will be used.
+
+ The canonical format of IPv6 addresses uses the compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture
+ RFC 4007: IPv6 Scoped Address Architecture
+ RFC 5952: A Recommendation for IPv6 Address Text Representation";
+ }
+
+ typedef ip-prefix {
+ type union {
+ type inet:ipv4-prefix;
+ type inet:ipv6-prefix;
+ }
+ description
+ "The ip-prefix type represents an IP prefix and is IP
+ version neutral. The format of the textual representations
+ implies the IP version.";
+ }
+
+ typedef ipv4-prefix {
+ type string {
+ pattern
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+ }
+ description
+ "The ipv4-prefix type represents an IPv4 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal to 32.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The canonical format of an IPv4 prefix has all bits of
+ the IPv4 address set to zero that are not part of the
+ IPv4 prefix.";
+ }
+
+ typedef ipv6-prefix {
+ type string {
+ pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+ pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ + '(/.+)';
+ }
+ description
+ "The ipv6-prefix type represents an IPv6 address prefix.
+ The prefix length is given by the number following the
+ slash character and must be less than or equal 128.
+
+ A prefix length value of n corresponds to an IP address
+ mask that has n contiguous 1-bits from the most
+ significant bit (MSB) and all other bits set to 0.
+
+ The IPv6 address should have all bits that do not belong
+ to the prefix set to zero.
+
+ The canonical format of an IPv6 prefix has all bits of
+ the IPv6 address set to zero that are not part of the
+ IPv6 prefix. Furthermore, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** collection of domain name and URI types ***/
+
+ typedef domain-name {
+ type string {
+ pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ + '|\.';
+ length "1..253";
+ }
+ description
+ "The domain-name type represents a DNS domain name. The
+ name SHOULD be fully qualified whenever possible.
+
+ Internet domain names are only loosely specified. Section
+ 3.5 of RFC 1034 recommends a syntax (modified in Section
+ 2.1 of RFC 1123). The pattern above is intended to allow
+ for current practice in domain name use, and some possible
+ future expansion. It is designed to hold various types of
+ domain names, including names used for A or AAAA records
+ (host names) and other records, such as SRV records. Note
+ that Internet host names have a stricter syntax (described
+ in RFC 952) than the DNS recommendations in RFCs 1034 and
+ 1123, and that systems that want to store host names in
+ schema nodes using the domain-name type are recommended to
+ adhere to this stricter standard to ensure interoperability.
+
+ The encoding of DNS names in the DNS protocol is limited
+ to 255 characters. Since the encoding consists of labels
+ prefixed by a length bytes and there is a trailing NULL
+ byte, only 253 characters can appear in the textual dotted
+ notation.
+
+ The description clause of schema nodes using the domain-name
+ type MUST describe when and how these names are resolved to
+ IP addresses. Note that the resolution of a domain-name value
+ may require to query multiple DNS records (e.g., A for IPv4
+ and AAAA for IPv6). The order of the resolution process and
+ which DNS record takes precedence can either be defined
+ explicitely or it may depend on the configuration of the
+ resolver.
+
+ Domain-name values use the US-ASCII encoding. Their canonical
+ format uses lowercase US-ASCII characters. Internationalized
+ domain names MUST be encoded in punycode as described in RFC
+ 3492";
+ reference
+ "RFC 952: DoD Internet Host Table Specification
+ RFC 1034: Domain Names - Concepts and Facilities
+ RFC 1123: Requirements for Internet Hosts -- Application
+ and Support
+ RFC 2782: A DNS RR for specifying the location of services
+ (DNS SRV)
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ typedef host {
+ type union {
+ type inet:ip-address;
+ type inet:domain-name;
+ }
+ description
+ "The host type represents either an IP address or a DNS
+ domain name.";
+ }
+
+ typedef uri {
+ type string;
+ description
+ "The uri type represents a Uniform Resource Identifier
+ (URI) as defined by STD 66.
+
+ Objects using the uri type MUST be in US-ASCII encoding,
+ and MUST be normalized as described by RFC 3986 Sections
+ 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
+ percent-encoding is removed, and all case-insensitive
+ characters are set to lowercase except for hexadecimal
+ digits, which are normalized to uppercase as described in
+ Section 6.2.2.1.
+
+ The purpose of this normalization is to help provide
+ unique URIs. Note that this normalization is not
+ sufficient to provide uniqueness. Two URIs that are
+ textually distinct after this normalization may still be
+ equivalent.
+
+ Objects using the uri type may restrict the schemes that
+ they permit. For example, 'data:' and 'urn:' schemes
+ might not be appropriate.
+
+ A zero-length URI is not a valid URI. This can be used to
+ express 'URI absent' where required.
+
+ In the value set and its semantics, this type is equivalent
+ to the Uri SMIv2 textual convention defined in RFC 5017.";
+ reference
+ "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+ Group: Uniform Resource Identifiers (URIs), URLs,
+ and Uniform Resource Names (URNs): Clarifications
+ and Recommendations
+ RFC 5017: MIB Textual Conventions for Uniform Resource
+ Identifiers (URIs)";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-restconf-monitoring@2017-01-26.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-restconf-monitoring@2017-01-26.yang
new file mode 100644
index 0000000..55c3cb1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-restconf-monitoring@2017-01-26.yang
@@ -0,0 +1,149 @@
+module ietf-restconf-monitoring {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring";
+ prefix "rcmon";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ Author: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Author: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Author: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+
+ description
+ "This module contains monitoring information for the
+ RESTCONF protocol.
+
+ Copyright (c) 2017 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 8040; see
+ the RFC itself for full legal notices.";
+
+ revision 2017-01-26 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 8040: RESTCONF Protocol.";
+ }
+
+ container restconf-state {
+ config false;
+ description
+ "Contains RESTCONF protocol monitoring information.";
+
+ container capabilities {
+ description
+ "Contains a list of protocol capability URIs.";
+
+ leaf-list capability {
+ type inet:uri;
+ description
+ "A RESTCONF protocol capability URI.";
+ }
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description
+ "The stream name.";
+ reference
+ "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "Description of stream content.";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ default false;
+ description
+ "Indicates if replay buffer is supported for this stream.
+ If 'true', then the server MUST support the 'start-time'
+ and 'stop-time' query parameters for this stream.";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ when "../replay-support" {
+ description
+ "Only present if notification replay is supported.";
+ }
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ list access {
+ key encoding;
+ min-elements 1;
+ description
+ "The server will create an entry in this list for each
+ encoding format that is supported for this stream.
+ The media type 'text/event-stream' is expected
+ for all event streams. This list identifies the
+ subtypes supported for this stream.";
+
+ leaf encoding {
+ type string;
+ description
+ "This is the secondary encoding format within the
+ 'text/event-stream' encoding used by all streams.
+ The type 'xml' is supported for XML encoding.
+ The type 'json' is supported for JSON encoding.";
+ }
+
+ leaf location {
+ type inet:uri;
+ mandatory true;
+ description
+ "Contains a URL that represents the entry point
+ for establishing notification delivery via
+ server-sent events.";
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-restconf@2017-01-26.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-restconf@2017-01-26.yang
new file mode 100644
index 0000000..dc54388
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-restconf@2017-01-26.yang
@@ -0,0 +1,279 @@
+module ietf-restconf {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "rc";
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ Author: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Author: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Author: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for basic RESTCONF media type definitions used in
+ RESTCONF protocol messages.
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The 'restconf-media-type' YANG extension statement
+ provides a normative syntax for XML and JSON
+ message-encoding purposes.
+
+ Copyright (c) 2017 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 8040; see
+ the RFC itself for full legal notices.";
+
+ revision 2017-01-26 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 8040: RESTCONF Protocol.";
+ }
+
+ extension yang-data {
+ argument name {
+ yin-element true;
+ }
+ description
+ "This extension is used to specify a YANG data template that
+ represents conceptual data defined in YANG. It is
+ intended to describe hierarchical data independent of
+ protocol context or specific message-encoding format.
+ Data definition statements within a yang-data extension
+ specify the generic syntax for the specific YANG data
+ template, whose name is the argument of the 'yang-data'
+ extension statement.
+
+ Note that this extension does not define a media type.
+ A specification using this extension MUST specify the
+ message-encoding rules, including the content media type.
+
+ The mandatory 'name' parameter value identifies the YANG
+ data template that is being defined. It contains the
+ template name.
+
+ This extension is ignored unless it appears as a top-level
+ statement. It MUST contain data definition statements
+ that result in exactly one container data node definition.
+ An instance of a YANG data template can thus be translated
+ into an XML instance document, whose top-level element
+ corresponds to the top-level container.
+
+ The module name and namespace values for the YANG module using
+ the extension statement are assigned to instance document data
+ conforming to the data definition statements within
+ this extension.
+
+ The substatements of this extension MUST follow the
+ 'data-def-stmt' rule in the YANG ABNF.
+
+ The XPath document root is the extension statement itself,
+ such that the child nodes of the document root are
+ represented by the data-def-stmt substatements within
+ this extension. This conceptual document is the context
+ for the following YANG statements:
+
+ - must-stmt
+ - when-stmt
+ - path-stmt
+ - min-elements-stmt
+ - max-elements-stmt
+ - mandatory-stmt
+ - unique-stmt
+ - ordered-by
+ - instance-identifier data type
+
+ The following data-def-stmt substatements are constrained
+ when used within a 'yang-data' extension statement.
+
+ - The list-stmt is not required to have a key-stmt defined.
+ - The if-feature-stmt is ignored if present.
+ - The config-stmt is ignored if present.
+ - The available identity values for any 'identityref'
+ leaf or leaf-list nodes are limited to the module
+ containing this extension statement and the modules
+ imported into that module.
+ ";
+ }
+
+ rc:yang-data yang-errors {
+ uses errors;
+ }
+
+ rc:yang-data yang-api {
+ uses restconf;
+ }
+
+ grouping errors {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch error report within a response message.";
+
+ container errors {
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference
+ "RFC 6241, Section 4.3.";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description
+ "The transport layer.";
+ }
+ enum rpc {
+ description
+ "The rpc or notification layer.";
+ }
+ enum protocol {
+ description
+ "The protocol operation layer.";
+ }
+ enum application {
+ description
+ "The server application layer.";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error-tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error-tag.";
+ }
+
+ leaf error-path {
+ type instance-identifier;
+ description
+ "The YANG instance identifier associated
+ with the error node.";
+ }
+
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ anydata error-info {
+ description
+ "This anydata value MUST represent a container with
+ zero or more data nodes representing additional
+ error information.";
+ }
+ }
+ }
+ }
+
+ grouping restconf {
+ description
+ "Conceptual grouping representing the RESTCONF
+ root resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the RESTCONF
+ root resource.";
+
+ container data {
+ description
+ "Container representing the datastore resource.
+ Represents the conceptual root of all state data
+ and configuration data supported by the server.
+ The child nodes of this container can be any data
+ resources that are defined as top-level data nodes
+ from the YANG modules advertised by the server in
+ the 'ietf-yang-library' module.";
+ }
+
+ container operations {
+ description
+ "Container for all operation resources.
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG 'rpc' statement.
+
+ For example, the 'system-restart' RPC operation defined
+ in the 'ietf-system' module would be represented as
+ an empty leaf in the 'ietf-system' namespace. This is
+ a conceptual leaf and will not actually be found in
+ the module:
+
+ module ietf-system {
+ leaf system-reset {
+ type empty;
+ }
+ }
+
+ To invoke the 'system-restart' RPC operation:
+
+ POST /restconf/operations/ietf-system:system-restart
+
+ To discover the RPC operations supported by the server:
+
+ GET /restconf/operations
+
+ In XML, the YANG module namespace identifies the module:
+
+ <system-restart
+ xmlns='urn:ietf:params:xml:ns:yang:ietf-system'/>
+
+ In JSON, the YANG module name identifies the module:
+
+ { 'ietf-system:system-restart' : [null] }
+ ";
+ }
+
+ leaf yang-library-version {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ config false;
+ mandatory true;
+ description
+ "Identifies the revision date of the 'ietf-yang-library'
+ module that is implemented by this RESTCONF server.
+ Indicates the year, month, and day in YYYY-MM-DD
+ numeric format.";
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-yang-library@2016-06-21.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-yang-library@2016-06-21.yang
new file mode 100644
index 0000000..bc466ee
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-yang-library@2016-06-21.yang
@@ -0,0 +1,208 @@
+module ietf-yang-library {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-library";
+ prefix "yanglib";
+ import ietf-yang-types {
+ prefix yang;
+ }
+ import ietf-inet-types {
+ prefix inet;
+ }
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+ WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+ WG Chair: Mahesh Jethanandani
+ <mailto:mjethanandani@gmail.com>
+ Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>";
+ description
+ "This module contains monitoring information about the YANG
+ modules and submodules that are used within a YANG-based
+ server.
+ Copyright (c) 2016 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+ This version of this YANG module is part of RFC 7895; see
+ the RFC itself for full legal notices.";
+ revision 2016-06-21 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 7895: YANG Module Library.";
+ }
+ /*
+ * Typedefs
+ */
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.";
+ }
+ /*
+ * Groupings
+ */
+ grouping module-list {
+ description
+ "The module data structure is represented as a grouping
+ so it can be reused in configuration or another monitoring
+ data structure.";
+ grouping common-leafs {
+ description
+ "Common parameters for YANG modules and submodules.";
+ leaf name {
+ type yang:yang-identifier;
+ description
+ "The YANG module or submodule name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module or submodule revision date.
+ A zero-length string is used if no revision statement
+ is present in the YANG module or submodule.";
+ }
+ }
+ grouping schema-leaf {
+ description
+ "Common schema leaf parameter for modules and submodules.";
+ leaf schema {
+ type inet:uri;
+ description
+ "Contains a URL that represents the YANG schema
+ resource for this module or submodule.
+ This leaf will only be present if there is a URL
+ available for retrieval of the schema for this entry.";
+ }
+ }
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one revision of one module
+ currently supported by the server.";
+ uses common-leafs;
+ uses schema-leaf;
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server, regardless of whether they are
+ defined in the module or any included submodule.";
+ }
+ list deviation {
+ key "name revision";
+ description
+ "List of YANG deviation module names and revisions
+ used by this server to modify the conformance of
+ the module associated with this entry. Note that
+ the same module can be used for deviations for
+ multiple modules, so the same entry MAY appear
+ within multiple 'module' entries.
+ The deviation module MUST be present in the 'module'
+ list, with the same name and revision values.
+ The 'conformance-type' value will be 'implement' for
+ the deviation module.";
+ uses common-leafs;
+ }
+ leaf conformance-type {
+ type enumeration {
+ enum implement {
+ description
+ "Indicates that the server implements one or more
+ protocol-accessible objects defined in the YANG module
+ identified in this entry. This includes deviation
+ statements defined in the module.
+ For YANG version 1.1 modules, there is at most one
+ module entry with conformance type 'implement' for a
+ particular module name, since YANG 1.1 requires that,
+ at most, one revision of a module is implemented.
+ For YANG version 1 modules, there SHOULD NOT be more
+ than one module entry for a particular module name.";
+ }
+ enum import {
+ description
+ "Indicates that the server imports reusable definitions
+ from the specified revision of the module but does
+ not implement any protocol-accessible objects from
+ this revision.
+ Multiple module entries for the same module name MAY
+ exist. This can occur if multiple modules import the
+ same module but specify different revision dates in
+ the import statements.";
+ }
+ }
+ mandatory true;
+ description
+ "Indicates the type of conformance the server is claiming
+ for the YANG module identified by this entry.";
+ }
+ list submodule {
+ key "name revision";
+ description
+ "Each entry represents one submodule within the
+ parent module.";
+ uses common-leafs;
+ uses schema-leaf;
+ }
+ }
+ }
+ /*
+ * Operational state data nodes
+ */
+ container modules-state {
+ config false;
+ description
+ "Contains YANG module monitoring information.";
+ leaf module-set-id {
+ type string;
+ mandatory true;
+ description
+ "Contains a server-specific identifier representing
+ the current set of modules and submodules. The
+ server MUST change the value of this leaf if the
+ information represented by the 'module' list instances
+ has changed.";
+ }
+ uses module-list;
+ }
+ /*
+ * Notifications
+ */
+ notification yang-library-change {
+ description
+ "Generated when the set of modules and submodules supported
+ by the server has changed.";
+ leaf module-set-id {
+ type leafref {
+ path "/yanglib:modules-state/yanglib:module-set-id";
+ }
+ mandatory true;
+ description
+ "Contains the module-set-id value representing the
+ set of modules and submodules supported at the server at
+ the time the notification is generated.";
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-yang-types.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-yang-types.yang
new file mode 100644
index 0000000..c3f952c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/impl/ietf-yang-types.yang
@@ -0,0 +1,417 @@
+ module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: David Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2010 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms contained in, the Simplified BSD License set forth in Section
+ 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+
+
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined by the 'identifier'
+ rule in Section 12 of RFC 6020. An identifier must
+ start with an alphabetic character or an underscore
+ followed by an arbitrary sequence of alphabetic or
+ numeric characters, underscores, hyphens, or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lowercase or uppercase character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using the
+ time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually referring
+ to the notion of local time) uses the time-offset -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence happened.
+ The specific occurrence must be defined in the description
+ of any schema node defined using this type. When the specific
+ occurrence occurred prior to the last time the associated
+ timeticks attribute was zero, then the timestamp value is
+ zero. Note that this requires all timestamp values to be
+ reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ }
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/deserializer/deserializer-test-included.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/deserializer/deserializer-test-included.yang
new file mode 100644
index 0000000..b46898c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/deserializer/deserializer-test-included.yang
@@ -0,0 +1,22 @@
+module deserializer-test-included {
+ namespace "deserializer:test:included";
+ prefix "dti";
+ yang-version 1;
+
+ revision 2016-06-06 {
+ description
+ "Initial revision.";
+ }
+
+ list augmented-list {
+ key list-key;
+
+ leaf list-key {
+ type uint16;
+ }
+
+ leaf list-value {
+ type string;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/deserializer/deserializer-test.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/deserializer/deserializer-test.yang
new file mode 100644
index 0000000..38f989e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/deserializer/deserializer-test.yang
@@ -0,0 +1,90 @@
+module deserializer-test {
+ namespace "deserializer:test";
+ prefix "dt";
+ yang-version 1;
+
+ import deserializer-test-included { prefix dti; revision-date 2016-06-06; }
+
+ revision 2016-06-06 {
+ description
+ "Initial revision.";
+ }
+
+ container contA {
+ leaf-list leaf-list-A {
+ type string;
+ }
+
+ leaf leaf-A {
+ type string;
+ }
+
+ list list-A {
+ key list-key;
+
+ leaf list-key {
+ type uint8;
+ }
+
+ leaf-list leaf-list-AA {
+ type string;
+ }
+ }
+ }
+
+ leaf-list leaf-list-0 {
+ type boolean;
+ }
+
+ leaf leaf-0 {
+ type string;
+ }
+
+ list list-no-key {
+ leaf name {
+ type string;
+ }
+
+ leaf number {
+ type uint8;
+ }
+ }
+
+ list list-one-key {
+ key name;
+
+ leaf name {
+ type string;
+ }
+
+ leaf number {
+ type uint8;
+ }
+ }
+
+ list list-multiple-keys {
+ key "name number enabled";
+
+ leaf name {
+ type string;
+ }
+
+ leaf number {
+ type uint8;
+ }
+
+ leaf enabled {
+ type boolean;
+ }
+
+ leaf string-value {
+ type string;
+ }
+ }
+
+ augment "/dti:augmented-list" {
+ leaf augmented-leaf {
+ type string;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/list-test.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/list-test.yang
new file mode 100644
index 0000000..981e6fe
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/list-test.yang
@@ -0,0 +1,39 @@
+module list-test {
+ namespace "list:test";
+ prefix "listt";
+
+ revision 2016-04-29 {
+ description
+ "Initial revision.";
+ }
+
+ container top {
+ list list1 {
+ key "key1 key2 key3";
+ leaf key1 {
+ type string;
+ }
+ leaf key2 {
+ type string;
+ }
+ leaf key3 {
+ type string;
+ }
+ list list2 {
+ key "key4 key5";
+ leaf key4 {
+ type string;
+ }
+ leaf key5 {
+ type string;
+ }
+ leaf result {
+ type string;
+ }
+ }
+ }
+ leaf-list Y {
+ type uint32;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/serializer/serializer-test-included.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/serializer/serializer-test-included.yang
new file mode 100644
index 0000000..c404aeb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/serializer/serializer-test-included.yang
@@ -0,0 +1,22 @@
+module serializer-test-included {
+ namespace "serializer:test:included";
+ prefix "sti";
+ yang-version 1;
+
+ revision 2016-06-06 {
+ description
+ "Initial revision.";
+ }
+
+ list augmented-list {
+ key list-key;
+
+ leaf list-key {
+ type uint16;
+ }
+
+ leaf list-value {
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/serializer/serializer-test.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/serializer/serializer-test.yang
new file mode 100644
index 0000000..691e4dc
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/restconf/parser/serializer/serializer-test.yang
@@ -0,0 +1,86 @@
+module serializer-test {
+ namespace "serializer:test";
+ prefix "st";
+ yang-version 1;
+
+ import serializer-test-included { prefix sti; revision-date 2016-06-06; }
+
+ revision 2016-06-06 {
+ description
+ "Initial revision.";
+ }
+
+ container contA {
+ leaf-list leaf-list-A {
+ type string;
+ }
+
+ leaf leaf-A {
+ type string;
+ }
+
+ list list-A {
+ key list-key;
+
+ leaf list-key {
+ type uint8;
+ }
+
+ leaf-list leaf-list-AA {
+ type string;
+ }
+ }
+ }
+
+ leaf-list leaf-list-0 {
+ type boolean;
+ }
+
+ leaf leaf-0 {
+ type string;
+ }
+
+ list list-no-key {
+ leaf name {
+ type string;
+ }
+
+ leaf number {
+ type uint8;
+ }
+ }
+
+ list list-one-key {
+ key name;
+
+ leaf name {
+ type string;
+ }
+
+ leaf number {
+ type uint8;
+ }
+ }
+
+ list list-multiple-keys {
+ key "name number enabled";
+
+ leaf name {
+ type string;
+ }
+
+ leaf number {
+ type uint8;
+ }
+
+ leaf enabled {
+ type boolean;
+ }
+ }
+
+ augment "/sti:augmented-list" {
+ leaf augmented-leaf {
+ type string;
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/streams/sal-remote@2014-01-14.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/streams/sal-remote@2014-01-14.yang
new file mode 100644
index 0000000..0f6aebf
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/streams/sal-remote@2014-01-14.yang
@@ -0,0 +1,112 @@
+module sal-remote {
+
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
+ prefix "sal-remote";
+
+ organization "Cisco Systems, Inc.";
+ contact "Martin Bobak <mbobak@cisco.com>";
+
+ description
+ "This module contains the definition of methods related to
+ sal remote model.
+
+ Copyright (c)2013 Cisco Systems, Inc. All rights reserved.
+
+ This program and the accompanying materials are made available
+ under the terms of the Eclipse Public License v1.0 which
+ accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html";
+
+ revision "2014-01-14" {
+ description
+ "Initial revision";
+ }
+
+
+ typedef q-name {
+ type string;
+ reference
+ "http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#QName";
+ }
+
+ rpc create-data-change-event-subscription {
+ input {
+ leaf path {
+ type instance-identifier;
+ description "Subtree path. ";
+ }
+ }
+ output {
+ leaf stream-name {
+ type string;
+ description "Notification stream name.";
+ }
+ }
+ }
+
+ rpc create-data-change-event-subscription2 {
+ input {
+ leaf path2 {
+ type instance-identifier;
+ description "Subtree path. ";
+ }
+ }
+ output {
+ leaf stream-name2 {
+ type string;
+ description "Notification stream name.";
+ }
+ }
+ }
+
+ notification data-changed-notification {
+ description "Data change notification.";
+ list data-change-event {
+ key path;
+ leaf path {
+ type instance-identifier;
+ }
+ leaf store {
+ type enumeration {
+ enum config;
+ enum operation;
+ }
+ }
+ leaf operation {
+ type enumeration {
+ enum created;
+ enum updated;
+ enum deleted;
+ }
+ }
+ anyxml data{
+ description "DataObject ";
+ }
+ }
+ }
+
+ rpc create-notification-stream {
+ input {
+ leaf-list notifications {
+ type q-name;
+ description "Notification QNames";
+ }
+ }
+ output {
+ leaf notification-stream-identifier {
+ type string;
+ description "Unique notification stream identifier, in which notifications will be propagated";
+ }
+ }
+ }
+
+ rpc begin-transaction{
+ output{
+ anyxml data-modification-transaction{
+ description "DataModificationTransaction xml";
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/streams/toaster.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/streams/toaster.yang
new file mode 100644
index 0000000..ad6b9b0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/streams/toaster.yang
@@ -0,0 +1,197 @@
+ module toaster {
+
+ yang-version 1;
+
+ namespace
+ "http://netconfcentral.org/ns/toaster";
+
+ prefix toast;
+
+ organization "Netconf Central";
+
+ contact
+ "Andy Bierman <andy@netconfcentral.org>";
+
+ description
+ "YANG version of the TOASTER-MIB.";
+
+ revision "2009-11-20" {
+ description
+ "Toaster module in progress.";
+ }
+
+
+ identity toast-type {
+ description
+ "Base for all bread types supported by the toaster.
+ New bread types not listed here nay be added in the
+ future.";
+ }
+
+ identity white-bread {
+ base toast:toast-type;
+ description "White bread.";
+ }
+
+ identity wheat-bread {
+ base toast-type;
+ description "Wheat bread.";
+ }
+
+ identity wonder-bread {
+ base toast-type;
+ description "Wonder bread.";
+ }
+
+ identity frozen-waffle {
+ base toast-type;
+ description "Frozen waffle.";
+ }
+
+ identity frozen-bagel {
+ base toast-type;
+ description "Frozen bagel.";
+ }
+
+ identity hash-brown {
+ base toast-type;
+ description "Hash browned potatos.";
+ }
+
+ typedef DisplayString {
+ type string {
+ length "0 .. 255";
+ }
+ description
+ "YANG version of the SMIv2 DisplayString TEXTUAL-CONVENTION.";
+ reference
+ "RFC 2579, section 2.";
+
+ }
+
+ container toaster {
+ presence
+ "Indicates the toaster service is available";
+ description
+ "Top-level container for all toaster database objects.";
+ leaf toasterManufacturer {
+ type DisplayString;
+ config false;
+ mandatory true;
+ description
+ "The name of the toaster's manufacturer. For instance,
+ Microsoft Toaster.";
+ }
+
+ leaf toasterModelNumber {
+ type DisplayString;
+ config false;
+ mandatory true;
+ description
+ "The name of the toaster's model. For instance,
+ Radiant Automatic.";
+ }
+
+ leaf toasterStatus {
+ type enumeration {
+ enum "up" {
+ value 1;
+ description
+ "The toaster knob position is up.
+ No toast is being made now.";
+ }
+ enum "down" {
+ value 2;
+ description
+ "The toaster knob position is down.
+ Toast is being made now.";
+ }
+ }
+ config false;
+ mandatory true;
+ description
+ "This variable indicates the current state of
+ the toaster.";
+ }
+ } // container toaster
+
+ rpc make-toast {
+ description
+ "Make some toast.
+ The toastDone notification will be sent when
+ the toast is finished.
+ An 'in-use' error will be returned if toast
+ is already being made.
+ A 'resource-denied' error will be returned
+ if the toaster service is disabled.";
+ input {
+ leaf toasterDoneness {
+ type uint32 {
+ range "1 .. 10";
+ }
+ default '5';
+ description
+ "This variable controls how well-done is the
+ ensuing toast. It should be on a scale of 1 to 10.
+ Toast made at 10 generally is considered unfit
+ for human consumption; toast made at 1 is warmed
+ lightly.";
+ }
+
+ leaf toasterToastType {
+ type identityref {
+ base toast:toast-type;
+ }
+ default 'wheat-bread';
+ description
+ "This variable informs the toaster of the type of
+ material that is being toasted. The toaster
+ uses this information, combined with
+ toasterDoneness, to compute for how
+ long the material must be toasted to achieve
+ the required doneness.";
+ }
+ }
+ } // rpc make-toast
+
+ rpc testOutput {
+ output {
+ leaf textOut {
+ type string;
+ }
+ }
+ }
+
+ rpc cancel-toast {
+ description
+ "Stop making toast, if any is being made.
+ A 'resource-denied' error will be returned
+ if the toaster service is disabled.";
+ } // rpc cancel-toast
+
+ notification toastDone {
+ description
+ "Indicates that the toast in progress has completed.";
+ leaf toastStatus {
+ type enumeration {
+ enum "done" {
+ value 0;
+ description "The toast is done.";
+ }
+ enum "cancelled" {
+ value 1;
+ description
+ "The toast was cancelled.";
+ }
+ enum "error" {
+ value 2;
+ description
+ "The toaster service was disabled or
+ the toaster is broken.";
+ }
+ }
+ description
+ "Indicates the final toast status";
+ }
+ } // notification toastDone
+ } // module toaster
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/test-mount-point/yang/test-interface.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/test-mount-point/yang/test-interface.yang
new file mode 100644
index 0000000..7502f85
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/test-mount-point/yang/test-interface.yang
@@ -0,0 +1,30 @@
+module mount-interface {
+ yang-version 1;
+ namespace "urn:ietf:params:xml:ns:yang:mount-interface";
+ prefix "sn";
+
+ description
+ "test file";
+
+ revision "2014-07-01" {
+ description
+ "Initial revision";
+ reference "will be defined";
+ }
+
+ container interfaces {
+ list interface {
+ key "name";
+
+ leaf name {
+ type string;
+ }
+ leaf type {
+ type string;
+ }
+ leaf enabled {
+ type string;
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/test-mount-point/yang/test-interface2.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/test-mount-point/yang/test-interface2.yang
new file mode 100644
index 0000000..086d682
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/test-mount-point/yang/test-interface2.yang
@@ -0,0 +1,27 @@
+module mount-interface2 {
+ yang-version 1;
+ namespace "urn:ietf:params:xml:ns:yang:mount-interface2";
+ prefix "snn";
+
+ description
+ "test file";
+
+ revision "2014-08-01" {
+ description
+ "Initial revision";
+ reference "will be defined";
+ }
+
+ container class {
+ list student {
+ key "name";
+
+ leaf name {
+ type string;
+ }
+ leaf age {
+ type string;
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/block-data.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/block-data.xml
new file mode 100644
index 0000000..625b04d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/block-data.xml
@@ -0,0 +1,4 @@
+<block xmlns="urn:ietf:params:xml:ns:yang:test-interface">
+ <address>456</address>
+ <location>First</location>
+</block> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/data2.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/data2.xml
new file mode 100644
index 0000000..21712cb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/data2.xml
@@ -0,0 +1,4 @@
+<student xmlns="urn:ietf:params:xml:ns:yang:test-interface2">
+ <name>Vojtech</name>
+ <age>17</age>
+</student> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface.xml
new file mode 100644
index 0000000..755c8a9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface.xml
@@ -0,0 +1,8 @@
+<interfaces xmlns="urn:ietf:params:xml:ns:yang:test-interface">
+ <interface>
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+ </interface>
+</interfaces>
+
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface2.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface2.xml
new file mode 100644
index 0000000..05db4a5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface2.xml
@@ -0,0 +1,5 @@
+<interface>
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+</interface>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface3.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface3.xml
new file mode 100644
index 0000000..e59ba17
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/xml/test-interface3.xml
@@ -0,0 +1,6 @@
+<class xmlns="urn:ietf:params:xml:ns:yang:test-interface2">
+ <student>
+ <name>Thomas</name>
+ <age>23</age>
+ </student>
+</class>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/yang1/test-interface.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/yang1/test-interface.yang
new file mode 100644
index 0000000..d0699e2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/yang1/test-interface.yang
@@ -0,0 +1,49 @@
+module test-interface {
+ yang-version 1;
+ namespace "urn:ietf:params:xml:ns:yang:test-interface";
+ prefix "sn";
+
+ description
+ "test file";
+
+ revision "2014-07-01" {
+ description
+ "Initial revision";
+ reference "will be defined";
+ }
+
+ container interfaces {
+
+ container block {
+
+ leaf address {
+ type string;
+ }
+ leaf location {
+ type string;
+ }
+ }
+
+ list interface {
+ key "name";
+
+ list sub-interface {
+ key "sub-name";
+
+ leaf sub-name {
+ type string;
+ }
+ }
+
+ leaf name {
+ type string;
+ }
+ leaf type {
+ type string;
+ }
+ leaf enabled {
+ type string;
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/yang2/test-interface2.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/yang2/test-interface2.yang
new file mode 100644
index 0000000..13bc0eb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/test-config-data/yang2/test-interface2.yang
@@ -0,0 +1,27 @@
+module test-interface2 {
+ yang-version 1;
+ namespace "urn:ietf:params:xml:ns:yang:test-interface2";
+ prefix "snn";
+
+ description
+ "test file";
+
+ revision "2014-08-01" {
+ description
+ "Initial revision";
+ reference "will be defined";
+ }
+
+ container class {
+ list student {
+ key "name";
+
+ leaf name {
+ type string;
+ }
+ leaf age {
+ type string;
+ }
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/varioustest/xmldata.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/varioustest/xmldata.xml
new file mode 100644
index 0000000..5d45980
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/varioustest/xmldata.xml
@@ -0,0 +1,5 @@
+<cont xmlns="generalnamespace">
+ <cont1>
+ <lf1 xmlns:prefix="prefix:name" xmlns:prefix2="prefix2:name">/prefix:somepath1/prefix2:somepath2</lf1>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-container-yang/data-container.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-container-yang/data-container.yang
new file mode 100644
index 0000000..b038eb1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-container-yang/data-container.yang
@@ -0,0 +1,35 @@
+module data-container-yang {
+ namespace "data:container:yang";
+
+ prefix "dtconyg";
+ revision 2013-11-19 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type string;
+ }
+
+ leaf lf2 {
+ type string;
+ }
+
+ leaf lf3 {
+ type empty;
+ }
+
+ leaf-list lflst1 {
+ type string;
+ }
+ list lst1 {
+ leaf lf11 {
+ type string;
+ }
+ }
+ container cont1 {
+ leaf lf11 {
+ type uint8;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-container.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-container.xml
new file mode 100644
index 0000000..841d351
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-container.xml
@@ -0,0 +1,14 @@
+<cont>
+ <lf1>str0</lf1>
+ <lf2></lf2>
+ <lf3/>
+ <lflst1>121</lflst1>
+ <lflst1>131</lflst1>
+ <lflst1>str1</lflst1>
+ <lst1>
+ <lf11>str2</lf11>
+ </lst1>
+ <cont1>
+ <lf11>100</lf11>
+ </cont1>
+</cont>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list-yang/data-container.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list-yang/data-container.yang
new file mode 100644
index 0000000..3df3413
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list-yang/data-container.yang
@@ -0,0 +1,28 @@
+module data-container-yang {
+ namespace "data:container:yang";
+
+ prefix "dtconyg";
+ revision 2013-11-19 {
+ }
+
+ container cont {
+ list lst1 {
+ leaf lf11 {
+ type string;
+ }
+ leaf-list lflst11 {
+ type string;
+ }
+ list lst11 {
+ leaf lf111 {
+ type string;
+ }
+ }
+ container cont11 {
+ leaf lf111 {
+ type uint8;
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list-yang/data-list.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list-yang/data-list.yang
new file mode 100644
index 0000000..47e2a45
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list-yang/data-list.yang
@@ -0,0 +1,22 @@
+module data-list-yang {
+ namespace "data:list:yang";
+
+ prefix "dtlstyg";
+
+ import data-container-yang {
+ prefix "dtconyg";
+ revision-date 2013-11-19;
+ }
+
+
+ revision 2013-11-19 {
+ }
+
+
+
+ augment "/dtconyg:cont" {
+ leaf lf1 {
+ type string;
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list.xml
new file mode 100644
index 0000000..9c4256a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-list.xml
@@ -0,0 +1,21 @@
+<cont>
+ <lst1>
+ <lf11>str0</lf11>
+ <lflst11>121</lflst11>
+ <lflst11>131</lflst11>
+ <lflst11>str1</lflst11>
+ <lst11>
+ <lf111>str2</lf111>
+ </lst11>
+ <cont11>
+ <lf111>100</lf111>
+ </cont11>
+ </lst1>
+ <lst1>
+ <lflst11>221</lflst11>
+ <cont11>
+ <lf111>100</lf111>
+ </cont11>
+ </lst1>
+ <lf1>lf1</lf1>
+</cont>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-nmspc-in-attributes.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-nmspc-in-attributes.xml
new file mode 100644
index 0000000..848c020
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-nmspc-in-attributes.xml
@@ -0,0 +1,5 @@
+<cont xmlns:x="x:namespace" xmlns:y="y:namespace">
+ <cont1 xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11 xmlns:c="identity:module">c:iden</lf11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-of-several-modules/yang/module1.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-of-several-modules/yang/module1.yang
new file mode 100644
index 0000000..f6a81ae
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-of-several-modules/yang/module1.yang
@@ -0,0 +1,16 @@
+module module1 {
+ namespace "module:one";
+
+ prefix "m1";
+ revision 2014-01-17 {
+ }
+
+ container cont_m1 {
+ leaf lf1_m1 {
+ type string;
+ }
+ }
+ container contB_m1 {
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-of-several-modules/yang/module2.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-of-several-modules/yang/module2.yang
new file mode 100644
index 0000000..bdd8ece
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/data-of-several-modules/yang/module2.yang
@@ -0,0 +1,17 @@
+module module2 {
+ namespace "module:two";
+
+ prefix "m2";
+ revision 2014-01-17 {
+ }
+
+ container cont_m2 {
+ leaf lf1_m2 {
+ type string;
+ }
+ }
+ container contB_m2 {
+ }
+
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/empty-data.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/empty-data.xml
new file mode 100644
index 0000000..7d62b9e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/empty-data.xml
@@ -0,0 +1,8 @@
+<cont>
+ <lf1></lf1>
+ <lflst1></lflst1>
+ <lflst1></lflst1>
+ <lst1>
+ <lf11></lf11>
+ </lst1>
+</cont>
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/identity-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/identity-module.yang
new file mode 100644
index 0000000..09a34c5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/identity-module.yang
@@ -0,0 +1,10 @@
+module identity-module {
+ namespace "identity:module";
+
+ prefix "idemod";
+ revision 2013-12-02 {
+ }
+
+ identity iden {
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/identityref-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/identityref-module.yang
new file mode 100644
index 0000000..e0ef1bb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/identityref-module.yang
@@ -0,0 +1,21 @@
+module identityref-module {
+ namespace "identityref:module";
+
+ prefix "iderefmod";
+
+ import identity-module {prefix idemo; revision-date 2013-12-02;}
+
+ revision 2013-12-02 {
+ }
+
+ container cont {
+ container cont1 {
+ leaf lf11 {
+ type identityref {
+ base "idemo:iden";
+ }
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml
new file mode 100644
index 0000000..ebf7ac6
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml
@@ -0,0 +1,5 @@
+<cont xmlns="general:module" xmlns:x="x:namespace" xmlns:y="y:namespace">
+ <cont1 xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11 xmlns="identityref:module" xmlns:c="c:namespace">iden</lf11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml
new file mode 100644
index 0000000..3fe1e4b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml
@@ -0,0 +1,5 @@
+<cont xmlns:x="x:namespace" xmlns:y="y:namespace">
+ <cont1 xmlns="identityref:module" xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11 xmlns:c="c:namespace">iden</lf11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-element.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-element.xml
new file mode 100644
index 0000000..76de72d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-element.xml
@@ -0,0 +1,5 @@
+<cont xmlns="identityref:module" xmlns:x="x:namespace" xmlns:y="y:namespace">
+ <cont1 xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11 xmlns:c="identity:module">c:iden</lf11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml
new file mode 100644
index 0000000..30a5418
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml
@@ -0,0 +1,5 @@
+<cont xmlns="identityref:module" xmlns:x="x:namespace" xmlns:y="y:namespace">
+ <cont1 xmlns:c="identity:module" xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11>z:iden</lf11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml
new file mode 100644
index 0000000..7d31fa7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml
@@ -0,0 +1,5 @@
+<cont>
+ <cont1>
+ <lf11>x:iden</lf11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml
new file mode 100644
index 0000000..c65df1a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml
@@ -0,0 +1,5 @@
+<cont>
+ <cont1>
+ <lf11>iden</lf11>
+ </cont1>
+</cont> \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/general-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/general-module.yang
new file mode 100644
index 0000000..f1a1ea6
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/general-module.yang
@@ -0,0 +1,14 @@
+module general-module {
+ namespace "general:module";
+
+ prefix "genmod";
+ revision 2013-12-12 {
+ }
+
+ container cont {
+ container cont1 {
+ }
+ }
+
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/identity-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/identity-module.yang
new file mode 100644
index 0000000..09a34c5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/identity-module.yang
@@ -0,0 +1,10 @@
+module identity-module {
+ namespace "identity:module";
+
+ prefix "idemod";
+ revision 2013-12-02 {
+ }
+
+ identity iden {
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/identityref-module.yang b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/identityref-module.yang
new file mode 100644
index 0000000..8fd9002
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/identityref/yang-augments/identityref-module.yang
@@ -0,0 +1,20 @@
+module identityref-module {
+ namespace "identityref:module";
+
+ prefix "iderefmod";
+
+ import identity-module {prefix idemo; revision-date 2013-12-02;}
+ import general-module {prefix gmo; revision-date 2013-12-12;}
+
+ revision 2013-12-02 {
+ }
+
+ augment "/gmo:cont/gmo:cont1" {
+ leaf lf11 {
+ type identityref {
+ base "idemo:iden";
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/leafref/leafref-module b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/leafref/leafref-module
new file mode 100644
index 0000000..6fe770b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/leafref/leafref-module
@@ -0,0 +1,61 @@
+module leafref-module {
+ namespace "leafref:module";
+
+ prefix "lfrfmo";
+ revision 2013-11-18 {
+ }
+
+ identity base {}
+
+ container cont {
+ leaf lf1 {
+ type int32;
+ }
+ leaf lf2 {
+ type leafref {
+ path "/cont/lf1";
+ }
+ }
+
+ leaf lf-ident {
+ type identityref {
+ base "lfrfmo:base";
+ }
+ }
+
+ leaf lf-ident-ref {
+ type leafref {
+ path "/cont/lf-ident";
+ }
+ }
+
+ leaf lf-ident-ref-relative {
+ type leafref {
+ path "../lf-ident";
+ }
+ }
+
+ leaf lf-ident-ref-relative-cnd {
+ type leafref {
+ path "/lfrfmo:cont/lfrfmo:lis[lfrfmo:id='abc']/lf-ident-ref";
+ }
+ }
+
+
+ list lis {
+ key "id";
+
+ leaf id {
+ type string;
+ }
+
+ leaf lf-ident-ref {
+ type leafref {
+ path "/cont/lf-ident";
+ }
+ }
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/leafref/xml/data.xml b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/leafref/xml/data.xml
new file mode 100644
index 0000000..c3071e5
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/resources/xml-to-cnsn/leafref/xml/data.xml
@@ -0,0 +1,8 @@
+<cont>
+ <lf1>121</lf1>
+ <lf2>121</lf2>
+ <lf-ident xmlns:a="leafref:module">a:base</lf-ident>
+ <lf-ident-ref xmlns:a="leafref:module">a:base</lf-ident-ref>
+ <lf-ident-ref-relative xmlns:a="leafref:module">a:base</lf-ident-ref-relative>
+ <lf-ident-ref-relative-cnd xmlns:a="leafref:module">a:base</lf-ident-ref-relative-cnd>
+</cont> \ No newline at end of file