From bdcd6c4baea3357499a1fcdff459259b56373baa Mon Sep 17 00:00:00 2001 From: Jozef Gloncak Date: Mon, 30 Jun 2014 15:58:56 +0200 Subject: [PATCH] BUG 1082 Migrate sal-rest-connector to Async Data Broker API Rework of sal-rest-connector project to support Async Data Broker API Change-Id: I73804418a04445b236d12693e493a11850dd94dd Signed-off-by: Jozef Gloncak --- opendaylight/commons/opendaylight/pom.xml | 5 + .../distribution/opendaylight/pom.xml | 4 + .../md-sal/sal-rest-connector/pom.xml | 5 + .../rest/connector/RestConnectorModule.java | 2 + .../connector/RestConnectorModuleFactory.java | 1 - .../sal/rest/api/RestconfService.java | 16 +- .../controller/sal/rest/impl/JsonMapper.java | 6 +- .../impl/JsonToCompositeNodeProvider.java | 6 +- .../sal/rest/impl/RestconfProviderImpl.java | 11 +- .../rest/impl/XmlToCompositeNodeProvider.java | 10 +- .../rest/impl/XmlToCompositeNodeReader.java | 27 +- .../XmlToNormalizedNodeReaderWithSchema.java | 352 +++++++++++++ .../sal/restconf/impl/BrokerFacade.java | 262 +++++----- .../sal/restconf/impl/ControllerContext.java | 35 +- .../impl/InstanceIdWithSchemaNode.java | 8 +- .../sal/restconf/impl/RestCodec.java | 18 +- .../sal/restconf/impl/RestconfImpl.java | 462 +++++++++++++----- .../sal/restconf/impl/StructuredData.java | 10 +- .../rpc/impl/MountPointRpcExecutor.java | 15 +- .../streams/listeners/ListenerAdapter.java | 69 ++- .../sal/streams/listeners/Notificator.java | 37 +- .../src/main/yang/sal-remote-augment.yang | 31 ++ .../json/test/CnSnJsonBasicYangTypesTest.java | 7 +- .../to/json/test/CnSnJsonChoiceCaseTest.java | 13 +- .../test/CnSnToJsonBasicDataTypesTest.java | 12 +- .../test/CnSnToJsonIncorrectTopLevelTest.java | 9 +- .../to/json/test/CnSnToJsonLeafrefType.java | 8 +- .../json/test/CnSnToJsonWithAugmentTest.java | 8 +- .../to/cnsn/test/RestPutListDataTest.java | 14 +- .../cnsn/test/JsonIdentityrefToCnSnTest.java | 11 +- .../to/cnsn/test/JsonLeafrefToCnSnTest.java | 11 +- .../json/to/cnsn/test/JsonToCnSnTest.java | 59 ++- .../restconf/impl/test/BrokerFacadeTest.java | 266 ++++------ .../impl/test/InvokeRpcMethodTest.java | 10 +- .../MultipleEqualNamesForDataNodesTest.java | 10 +- .../impl/test/RestDeleteOperationTest.java | 21 +- .../impl/test/RestGetOperationTest.java | 197 +++++--- .../impl/test/RestPostOperationTest.java | 84 ++-- .../impl/test/RestPutOperationTest.java | 65 ++- .../restconf/impl/test/RestconfImplTest.java | 14 +- .../sal/restconf/impl/test/TestUtils.java | 165 ++++++- .../impl/test/URIParametersParsing.java | 101 ++++ .../sal/restconf/impl/test/URITest.java | 11 +- ...mlAndJsonToCnSnInstanceIdentifierTest.java | 21 +- .../test/XmlAndJsonToCnSnLeafRefTest.java | 12 +- .../impl/websockets/test/RestStream.java | 18 +- .../test/XmlAugmentedElementToCnSnTest.java | 11 +- .../to/cnsn/test/XmlLeafrefToCnSnTest.java | 74 +-- .../impl/xml/to/cnsn/test/XmlToCnSnTest.java | 19 +- .../opendaylight-inventory.yang | 19 + .../sal-remote-augment.yang | 31 ++ .../sal-remote@2014-01-14.yang | 98 ++++ 52 files changed, 1900 insertions(+), 891 deletions(-) create mode 100644 opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToNormalizedNodeReaderWithSchema.java create mode 100644 opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang create mode 100644 opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java create mode 100644 opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/opendaylight-inventory.yang create mode 100644 opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang create mode 100644 opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote@2014-01-14.yang diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index be88e4a505..9468133db8 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -1572,6 +1572,11 @@ util ${yangtools.version} + + org.opendaylight.yangtools + yang-data-composite-node + ${yangtools.version} + diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 541c1300f3..1d579ebe42 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -1214,6 +1214,10 @@ org.opendaylight.yangtools yang-parser-impl + + org.opendaylight.yangtools + yang-data-composite-node + org.opendaylight.yangtools.model diff --git a/opendaylight/md-sal/sal-rest-connector/pom.xml b/opendaylight/md-sal/sal-rest-connector/pom.xml index 09fb5b3677..2856a302d2 100644 --- a/opendaylight/md-sal/sal-rest-connector/pom.xml +++ b/opendaylight/md-sal/sal-rest-connector/pom.xml @@ -105,6 +105,11 @@ org.opendaylight.controller sal-core-spi + + org.opendaylight.yangtools + yang-data-composite-node + 0.6.2-SNAPSHOT + diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModule.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModule.java index 582c657868..52115a8f32 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModule.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModule.java @@ -2,6 +2,7 @@ package org.opendaylight.controller.config.yang.md.sal.rest.connector; import org.opendaylight.controller.sal.rest.impl.RestconfProviderImpl; + public class RestConnectorModule extends org.opendaylight.controller.config.yang.md.sal.rest.connector.AbstractRestConnectorModule { public RestConnectorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { @@ -28,3 +29,4 @@ public class RestConnectorModule extends org.opendaylight.controller.config.yang return instance; } } + diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModuleFactory.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModuleFactory.java index 957b08f6ae..1964a17472 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModuleFactory.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModuleFactory.java @@ -9,7 +9,6 @@ */ package org.opendaylight.controller.config.yang.md.sal.rest.connector; - public class RestConnectorModuleFactory extends org.opendaylight.controller.config.yang.md.sal.rest.connector.AbstractRestConnectorModuleFactory { } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java index a6c4ea5ab8..9c149a21e6 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java @@ -23,6 +23,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import org.opendaylight.controller.sal.restconf.impl.StructuredData; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; /** * The URI hierarchy for the RESTCONF resources consists of an entry point container, 4 top-level resources, and 1 @@ -30,15 +31,18 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; *
    *
  • /restconf - {@link #getRoot()} *
      - *
    • /config - {@link #readConfigurationData(String)} {@link #updateConfigurationData(String, CompositeNode)} - * {@link #createConfigurationData(CompositeNode)} {@link #createConfigurationData(String, CompositeNode)} + *
    • /config - {@link #readConfigurationData(String)} + * {@link #updateConfigurationData(String, CompositeNode)} + * {@link #createConfigurationData(CompositeNode)} + * {@link #createConfigurationData(String, CompositeNode)} * {@link #deleteConfigurationData(String)} *
    • /operational - {@link #readOperationalData(String)} *
    • /modules - {@link #getModules()} *
        *
      • /module *
      - *
    • /operations - {@link #invokeRpc(String, CompositeNode)} {@link #invokeRpc(String, CompositeNode)} + *
    • /operations - {@link #invokeRpc(String, CompositeNode)} + * {@link #invokeRpc(String, CompositeNode)} *
    • /version (field) *
    *
@@ -119,19 +123,19 @@ public interface RestconfService { @Path("/config/{identifier:.+}") @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - public Response updateConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); + public Response updateConfigurationData(@Encoded @PathParam("identifier") String identifier, Node payload); @POST @Path("/config/{identifier:.+}") @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - public Response createConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); + public Response createConfigurationData(@Encoded @PathParam("identifier") String identifier, Node payload); @POST @Path("/config") @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - public Response createConfigurationData(CompositeNode payload); + public Response createConfigurationData(Node payload); @DELETE @Path("/config/{identifier:.+}") diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java index 34aa829b6f..863de10325 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java @@ -19,7 +19,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import javax.activation.UnsupportedDataTypeException; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue; @@ -52,9 +52,9 @@ import org.slf4j.LoggerFactory; class JsonMapper { private static final Logger LOG = LoggerFactory.getLogger(JsonMapper.class); - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; - public JsonMapper(final MountInstance mountPoint) { + public JsonMapper(final DOMMountPoint mountPoint) { this.mountPoint = mountPoint; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java index 2f3499e269..caff848180 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java @@ -22,14 +22,14 @@ import org.opendaylight.controller.sal.rest.api.RestconfService; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Provider @Consumes({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON, MediaType.APPLICATION_JSON }) -public enum JsonToCompositeNodeProvider implements MessageBodyReader { +public enum JsonToCompositeNodeProvider implements MessageBodyReader> { INSTANCE; private final static Logger LOG = LoggerFactory.getLogger(JsonToCompositeNodeProvider.class); @@ -41,7 +41,7 @@ public enum JsonToCompositeNodeProvider implements MessageBodyReader type, final Type genericType, + public Node readFrom(final Class> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType, final MultivaluedMap httpHeaders, final InputStream entityStream) throws IOException, WebApplicationException { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProviderImpl.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProviderImpl.java index adb176a65d..bef1be2ed1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProviderImpl.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProviderImpl.java @@ -9,12 +9,11 @@ package org.opendaylight.controller.sal.rest.impl; import java.util.Collection; import java.util.Collections; - +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.controller.sal.core.api.Provider; -import org.opendaylight.controller.sal.core.api.data.DataBrokerService; import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.controller.sal.core.api.mount.MountService; import org.opendaylight.controller.sal.rest.api.RestConnector; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; @@ -37,15 +36,15 @@ public class RestconfProviderImpl implements Provider, AutoCloseable, RestConnec @Override public void onSessionInitiated(ProviderSession session) { - DataBrokerService dataService = session.getService(DataBrokerService.class); + final DOMDataBroker domDataBroker = session.getService(DOMDataBroker.class); BrokerFacade.getInstance().setContext(session); - BrokerFacade.getInstance().setDataService(dataService); + BrokerFacade.getInstance().setDomDataBroker( domDataBroker); SchemaService schemaService = session.getService(SchemaService.class); listenerRegistration = schemaService.registerSchemaServiceListener(ControllerContext.getInstance()); ControllerContext.getInstance().setSchemas(schemaService.getGlobalContext()); - ControllerContext.getInstance().setMountService(session.getService(MountService.class)); + ControllerContext.getInstance().setMountService(session.getService(DOMMountPointService.class)); webSocketServerThread = new Thread(WebSocketServer.createInstance(port.getValue().intValue())); webSocketServerThread.setName("Web socket server on port " + port); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java index 31e9c96462..d56a32e36e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java @@ -23,25 +23,25 @@ import org.opendaylight.controller.sal.rest.api.RestconfService; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Provider @Consumes({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) -public enum XmlToCompositeNodeProvider implements MessageBodyReader { +public enum XmlToCompositeNodeProvider implements MessageBodyReader> { INSTANCE; - private final static Logger LOG = LoggerFactory.getLogger(XmlToCompositeNodeProvider.class); @Override - public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + public boolean isReadable(final Class type, final Type genericType, final Annotation[] annotations, + final MediaType mediaType) { return true; } @Override - public CompositeNode readFrom(Class type, Type genericType, Annotation[] annotations, + public Node readFrom(final Class> type, final Type genericType, final Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { XmlToCompositeNodeReader xmlReader = new XmlToCompositeNodeReader(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeReader.java index 413823f520..5944d6003e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeReader.java @@ -33,10 +33,11 @@ public class XmlToCompositeNodeReader { private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); private XMLEventReader eventReader; - public CompositeNodeWrapper read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException, - IOException { - // Get an XML stream which can be marked, and reset, so we can check and - // see if there is any content being provided. + public Node read(InputStream entityStream) throws XMLStreamException, + UnsupportedFormatException, + IOException { + //Get an XML stream which can be marked, and reset, so we can check and see if there is + //any content being provided. entityStream = getMarkableStream(entityStream); if (isInputStreamEmpty(entityStream)) { @@ -52,12 +53,8 @@ public class XmlToCompositeNodeReader { } } - if (eventReader.hasNext() && !isCompositeNodeEvent(eventReader.peek())) { - throw new UnsupportedFormatException("Root element of XML has to be composite element."); - } - final Stack> processingQueue = new Stack<>(); - CompositeNodeWrapper root = null; + NodeWrapper root = null; NodeWrapper element = null; while (eventReader.hasNext()) { final XMLEvent event = eventReader.nextEvent(); @@ -70,17 +67,15 @@ public class XmlToCompositeNodeReader { } NodeWrapper newNode = null; if (isCompositeNodeEvent(event)) { + newNode = resolveCompositeNodeFromStartElement(startElement); if (root == null) { - root = resolveCompositeNodeFromStartElement(startElement); - newNode = root; - } else { - newNode = resolveCompositeNodeFromStartElement(startElement); + root = newNode; } } else if (isSimpleNodeEvent(event)) { + newNode = resolveSimpleNodeFromStartElement(startElement); if (root == null) { - throw new UnsupportedFormatException("Root element of XML has to be composite element."); + root = newNode; } - newNode = resolveSimpleNodeFromStartElement(startElement); } if (newNode != null) { @@ -98,7 +93,7 @@ public class XmlToCompositeNodeReader { throw new UnsupportedFormatException("XML should contain only one root element"); } - return root; + return (Node) root; } /** diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToNormalizedNodeReaderWithSchema.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToNormalizedNodeReaderWithSchema.java new file mode 100644 index 0000000000..935d96cb12 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToNormalizedNodeReaderWithSchema.java @@ -0,0 +1,352 @@ +/* + * 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.rest.impl; + +import static com.google.common.base.Preconditions.checkArgument; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; +import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode; +import org.opendaylight.controller.sal.restconf.impl.NodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.RestCodec; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; +import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.Node; +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.LeafListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; + +public class XmlToNormalizedNodeReaderWithSchema { + + private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); + private XMLEventReader eventReader; + private InstanceIdWithSchemaNode iiWithSchema; + + public XmlToNormalizedNodeReaderWithSchema(final InstanceIdWithSchemaNode iiWithSchema) { + this.iiWithSchema = iiWithSchema; + } + + public Node read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException, IOException { + // Get an XML stream which can be marked, and reset, so we can check and see if there is + // any content being provided. + entityStream = getMarkableStream(entityStream); + + if (isInputStreamEmpty(entityStream)) { + return null; + } + + eventReader = xmlInputFactory.createXMLEventReader(entityStream); + if (eventReader.hasNext()) { + XMLEvent element = eventReader.peek(); + if (element.isStartDocument()) { + eventReader.nextEvent(); + } + } + + final Stack> processingQueue = new Stack<>(); + NodeWrapper root = null; + NodeWrapper element = null; + Stack processingQueueSchema = new Stack<>(); + + while (eventReader.hasNext()) { + final XMLEvent event = eventReader.nextEvent(); + + if (event.isStartElement()) { + final StartElement startElement = event.asStartElement(); + CompositeNodeWrapper compParentNode = null; + if (!processingQueue.isEmpty() && processingQueue.peek() instanceof CompositeNodeWrapper) { + compParentNode = (CompositeNodeWrapper) processingQueue.peek(); + findSchemaNodeForElement(startElement, processingQueueSchema); + } else { + processingQueueSchema = checkElementAndSchemaNodeNameAndNamespace(startElement, + iiWithSchema.getSchemaNode()); + DataSchemaNode currentSchemaNode = processingQueueSchema.peek(); + if (!(currentSchemaNode instanceof ListSchemaNode) + && !(currentSchemaNode instanceof ContainerSchemaNode)) { + throw new UnsupportedFormatException( + "Top level element has to be of type list or container schema node."); + } + } + + NodeWrapper newNode = null; + if (isCompositeNodeEvent(event)) { + newNode = resolveCompositeNodeFromStartElement(processingQueueSchema.peek().getQName()); + if (root == null) { + root = newNode; + } + } else if (isSimpleNodeEvent(event)) { + newNode = resolveSimpleNodeFromStartElement(processingQueueSchema.peek(), getValueOf(startElement)); + if (root == null) { + root = newNode; + } + } + + if (newNode != null) { + processingQueue.push(newNode); + if (compParentNode != null) { + compParentNode.addValue(newNode); + } + } + } else if (event.isEndElement()) { + element = processingQueue.pop(); +// if(((EndElement)event).getName().getLocalPart().equals + processingQueueSchema.pop(); + } + } + + if (!root.getLocalName().equals(element.getLocalName())) { + throw new UnsupportedFormatException("XML should contain only one root element"); + } + + return root.unwrap(); + } + + private void findSchemaNodeForElement(StartElement element, Stack processingQueueSchema) { + DataSchemaNode currentSchemaNode = processingQueueSchema.peek(); + if (currentSchemaNode instanceof DataNodeContainer) { + final URI realNamespace = getNamespaceFor(element); + final String realName = getLocalNameFor(element); + Map childNamesakes = resolveChildsWithNameAsElement( + ((DataNodeContainer) currentSchemaNode), realName); + DataSchemaNode childDataSchemaNode = childNamesakes.get(realNamespace); + if (childDataSchemaNode == null) { + throw new RestconfDocumentedException("Element " + realName + " has namespace " + realNamespace + + ". Available namespaces are: " + childNamesakes.keySet(), ErrorType.APPLICATION, + ErrorTag.INVALID_VALUE); + } + processingQueueSchema.push(childDataSchemaNode); + } else { + throw new RestconfDocumentedException("Element " + processingQueueSchema.peek().getQName().getLocalName() + + " should be data node container .", ErrorType.APPLICATION, ErrorTag.INVALID_VALUE); + } + + } + + /** + * Returns map of data schema node which are accesible by URI which have equal name + */ + private Map resolveChildsWithNameAsElement(final DataNodeContainer dataNodeContainer, + final String realName) { + final Map namespaceToDataSchemaNode = new HashMap(); + for (DataSchemaNode dataSchemaNode : dataNodeContainer.getChildNodes()) { + if (dataSchemaNode.equals(realName)) { + namespaceToDataSchemaNode.put(dataSchemaNode.getQName().getNamespace(), dataSchemaNode); + } + } + return namespaceToDataSchemaNode; + } + + private final Stack checkElementAndSchemaNodeNameAndNamespace(final StartElement startElement, + final DataSchemaNode node) { + checkArgument(startElement != null, "Start Element cannot be NULL!"); + final String expectedName = node.getQName().getLocalName(); + final String xmlName = getLocalNameFor(startElement); + final URI expectedNamespace = node.getQName().getNamespace(); + final URI xmlNamespace = getNamespaceFor(startElement); + if (!expectedName.equals(xmlName)) { + throw new RestconfDocumentedException("Xml element name: " + xmlName + "\nSchema node name: " + + expectedName, org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType.APPLICATION, + ErrorTag.INVALID_VALUE); + } + + if (xmlNamespace != null && !expectedNamespace.equals(xmlNamespace)) { + throw new RestconfDocumentedException("Xml element ns: " + xmlNamespace + "\nSchema node ns: " + + expectedNamespace, + org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType.APPLICATION, + ErrorTag.INVALID_VALUE); + } + Stack processingQueueSchema = new Stack<>(); + processingQueueSchema.push(node); + return processingQueueSchema; + } + + /** + * If the input stream is not markable, then it wraps the input stream with a buffered stream, which is mark able. + * That way we can check if the stream is empty safely. + * + * @param entityStream + * @return + */ + private InputStream getMarkableStream(InputStream entityStream) { + if (!entityStream.markSupported()) { + entityStream = new BufferedInputStream(entityStream); + } + return entityStream; + } + + private boolean isInputStreamEmpty(final InputStream entityStream) throws IOException { + boolean isEmpty = false; + entityStream.mark(1); + if (entityStream.read() == -1) { + isEmpty = true; + } + entityStream.reset(); + return isEmpty; + } + + private boolean isSimpleNodeEvent(final XMLEvent event) throws XMLStreamException { + checkArgument(event != null, "XML Event cannot be NULL!"); + if (event.isStartElement()) { + XMLEvent innerEvent = skipCommentsAndWhitespace(); + if (innerEvent != null && (innerEvent.isCharacters() || innerEvent.isEndElement())) { + return true; + } + } + return false; + } + + private boolean isCompositeNodeEvent(final XMLEvent event) throws XMLStreamException { + checkArgument(event != null, "XML Event cannot be NULL!"); + if (event.isStartElement()) { + XMLEvent innerEvent = skipCommentsAndWhitespace(); + if (innerEvent != null) { + if (innerEvent.isStartElement()) { + return true; + } + } + } + return false; + } + + private XMLEvent skipCommentsAndWhitespace() throws XMLStreamException { + while (eventReader.hasNext()) { + XMLEvent event = eventReader.peek(); + if (event.getEventType() == XMLStreamConstants.COMMENT) { + eventReader.nextEvent(); + continue; + } + + if (event.isCharacters()) { + Characters chars = event.asCharacters(); + if (chars.isWhiteSpace()) { + eventReader.nextEvent(); + continue; + } + } + return event; + } + return null; + } + + private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final QName qName) { + // checkArgument(startElement != null, "Start Element cannot be NULL!"); + CompositeNodeWrapper compositeNodeWrapper = new CompositeNodeWrapper("dummy"); + compositeNodeWrapper.setQname(qName); + return compositeNodeWrapper; + + } + + private SimpleNodeWrapper resolveSimpleNodeFromStartElement(final DataSchemaNode node, final String value) + throws XMLStreamException { + // checkArgument(startElement != null, "Start Element cannot be NULL!"); + Object deserializedValue = null; + + if (node instanceof LeafSchemaNode) { + TypeDefinition baseType = RestUtil.resolveBaseTypeFrom(((LeafSchemaNode) node).getType()); + deserializedValue = RestCodec.from(baseType, iiWithSchema.getMountPoint()).deserialize(value); + } else if (node instanceof LeafListSchemaNode) { + TypeDefinition baseType = RestUtil.resolveBaseTypeFrom(((LeafListSchemaNode) node).getType()); + deserializedValue = RestCodec.from(baseType, iiWithSchema.getMountPoint()).deserialize(value); + } + // String data; + // if (data == null) { + // return new EmptyNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement)); + // } + SimpleNodeWrapper simpleNodeWrapper = new SimpleNodeWrapper("dummy", deserializedValue); + simpleNodeWrapper.setQname(node.getQName()); + return simpleNodeWrapper; + } + + private String getValueOf(final StartElement startElement) throws XMLStreamException { + String data = null; + if (eventReader.hasNext()) { + final XMLEvent innerEvent = eventReader.peek(); + if (innerEvent.isCharacters()) { + final Characters chars = innerEvent.asCharacters(); + if (!chars.isWhiteSpace()) { + data = innerEvent.asCharacters().getData(); + data = data + getAdditionalData(eventReader.nextEvent()); + } + } else if (innerEvent.isEndElement()) { + if (startElement.getLocation().getCharacterOffset() == innerEvent.getLocation().getCharacterOffset()) { + data = null; + } else { + data = ""; + } + } + } + return data == null ? null : data.trim(); + } + + private String getAdditionalData(final XMLEvent event) throws XMLStreamException { + String data = ""; + if (eventReader.hasNext()) { + final XMLEvent innerEvent = eventReader.peek(); + if (innerEvent.isCharacters() && !innerEvent.isEndElement()) { + final Characters chars = innerEvent.asCharacters(); + if (!chars.isWhiteSpace()) { + data = innerEvent.asCharacters().getData(); + data = data + getAdditionalData(eventReader.nextEvent()); + } + } + } + return data; + } + + private String getLocalNameFor(final StartElement startElement) { + return startElement.getName().getLocalPart(); + } + + private URI getNamespaceFor(final StartElement startElement) { + String namespaceURI = startElement.getName().getNamespaceURI(); + return namespaceURI.isEmpty() ? null : URI.create(namespaceURI); + } + + private Object resolveValueOfElement(final String value, final StartElement startElement) { + // it could be instance-identifier Built-In Type + if (value.startsWith("/")) { + IdentityValuesDTO iiValue = RestUtil.asInstanceIdentifier(value, new RestUtil.PrefixMapingFromXml( + startElement)); + if (iiValue != null) { + return iiValue; + } + } + // it could be identityref Built-In Type + String[] namespaceAndValue = value.split(":"); + if (namespaceAndValue.length == 2) { + String namespace = startElement.getNamespaceContext().getNamespaceURI(namespaceAndValue[0]); + if (namespace != null && !namespace.isEmpty()) { + return new IdentityValuesDTO(namespace, namespaceAndValue[1], namespaceAndValue[0], value); + } + } + // it is not "prefix:value" but just "value" + return value; + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java index 861aaac3d8..be24fd26dd 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java @@ -7,38 +7,43 @@ */ package org.opendaylight.controller.sal.restconf.impl; -import com.google.common.util.concurrent.Futures; +import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION; +import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.ListenableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; - import javax.ws.rs.core.Response.Status; - -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; -import org.opendaylight.controller.sal.core.api.data.DataBrokerService; -import org.opendaylight.controller.sal.core.api.data.DataChangeListener; -import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BrokerFacade implements DataReader { +public class BrokerFacade { private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class); private final static BrokerFacade INSTANCE = new BrokerFacade(); - - private volatile DataBrokerService dataService; private volatile ConsumerSession context; + private DOMDataBroker domDataBroker; private BrokerFacade() { } @@ -47,154 +52,175 @@ public class BrokerFacade implements DataReader readConfigurationData(final YangInstanceIdentifier path) { + checkPreconditions(); + return readDataViaTransaction(domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path); + } - return dataService.readConfigurationData(path); + public NormalizedNode readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) { + final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); + if (domDataBrokerService.isPresent()) { + return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path); + } + throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); } - public CompositeNode readConfigurationDataBehindMountPoint(final MountInstance mountPoint, - final YangInstanceIdentifier path) { - this.checkPreconditions(); + // READ operational + public NormalizedNode readOperationalData(final YangInstanceIdentifier path) { + checkPreconditions(); + return readDataViaTransaction(domDataBroker.newReadOnlyTransaction(), OPERATIONAL, path); + } - LOG.trace("Read Configuration via Restconf: {}", path); + public NormalizedNode readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) { + final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); + if (domDataBrokerService.isPresent()) { + return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), OPERATIONAL, path); + } + throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); + } - return mountPoint.readConfigurationData(path); + // PUT configuration + public CheckedFuture commitConfigurationDataPut( + final YangInstanceIdentifier path, final NormalizedNode payload) { + checkPreconditions(); + return putDataViaTransaction(domDataBroker.newWriteOnlyTransaction(), CONFIGURATION, path, payload); } - @Override - public CompositeNode readOperationalData(final YangInstanceIdentifier path) { - this.checkPreconditions(); + public CheckedFuture commitConfigurationDataPut( + final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode payload) { + final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); + if (domDataBrokerService.isPresent()) { + return putDataViaTransaction(domDataBrokerService.get().newWriteOnlyTransaction(), CONFIGURATION, path, + payload); + } + throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); + } - BrokerFacade.LOG.trace("Read Operational via Restconf: {}", path); + // POST configuration + public CheckedFuture commitConfigurationDataPost( + final YangInstanceIdentifier path, final NormalizedNode payload) { + checkPreconditions(); + return postDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload); + } - return dataService.readOperationalData(path); + public CheckedFuture commitConfigurationDataPost( + final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode payload) { + final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); + if (domDataBrokerService.isPresent()) { + return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path, + payload); + } + throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); } - public CompositeNode readOperationalDataBehindMountPoint(final MountInstance mountPoint, + // DELETE configuration + public CheckedFuture commitConfigurationDataDelete( final YangInstanceIdentifier path) { - this.checkPreconditions(); - - BrokerFacade.LOG.trace("Read Operational via Restconf: {}", path); + checkPreconditions(); + return deleteDataViaTransaction(domDataBroker.newWriteOnlyTransaction(), CONFIGURATION, path); + } - return mountPoint.readOperationalData(path); + public CheckedFuture commitConfigurationDataDelete( + final DOMMountPoint mountPoint, final YangInstanceIdentifier path) { + final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); + if (domDataBrokerService.isPresent()) { + return deleteDataViaTransaction(domDataBrokerService.get().newWriteOnlyTransaction(), CONFIGURATION, path); + } + throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); } + // RPC public Future> invokeRpc(final QName type, final CompositeNode payload) { this.checkPreconditions(); return context.rpc(type, payload); } - public Future> commitConfigurationDataPut(final YangInstanceIdentifier path, - final CompositeNode payload) { + public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope, + final ListenerAdapter listener) { this.checkPreconditions(); - final DataModificationTransaction transaction = dataService.beginTransaction(); - BrokerFacade.LOG.trace("Put Configuration via Restconf: {}", path); - transaction.putConfigurationData(path, payload); - return transaction.commit(); - } + if (listener.isListening()) { + return; + } - public Future> commitConfigurationDataPutBehindMountPoint( - final MountInstance mountPoint, final YangInstanceIdentifier path, final CompositeNode payload) { - this.checkPreconditions(); + YangInstanceIdentifier path = listener.getPath(); + final ListenerRegistration registration = domDataBroker.registerDataChangeListener( + datastore, path, listener, scope); - final DataModificationTransaction transaction = mountPoint.beginTransaction(); - BrokerFacade.LOG.trace("Put Configuration via Restconf: {}", path); - transaction.putConfigurationData(path, payload); - return transaction.commit(); + listener.setRegistration(registration); } - public Future> commitConfigurationDataPost(final YangInstanceIdentifier path, - final CompositeNode payload) { - this.checkPreconditions(); - - final DataModificationTransaction transaction = dataService.beginTransaction(); - /* check for available Node in Configuration DataStore by path */ - CompositeNode availableNode = transaction.readConfigurationData(path); - if (availableNode != null) { - String errMsg = "Post Configuration via Restconf was not executed because data already exists"; - BrokerFacade.LOG.warn((new StringBuilder(errMsg)).append(" : ").append(path).toString()); - - throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL, - ErrorTag.DATA_EXISTS); + private NormalizedNode readDataViaTransaction(final DOMDataReadTransaction transaction, + LogicalDatastoreType datastore, YangInstanceIdentifier path) { + LOG.trace("Read " + datastore.name() + " via Restconf: {}", path); + final ListenableFuture>> listenableFuture = transaction.read(datastore, path); + if (listenableFuture != null) { + Optional> optional; + try { + LOG.debug("Reading result data from transaction."); + optional = listenableFuture.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RestconfDocumentedException("Problem to get data from transaction.", e.getCause()); + + } + if (optional != null) { + if (optional.isPresent()) { + return optional.get(); + } + } } - BrokerFacade.LOG.trace("Post Configuration via Restconf: {}", path); - transaction.putConfigurationData(path, payload); - return transaction.commit(); - } - - public Future> commitConfigurationDataPostBehindMountPoint( - final MountInstance mountPoint, final YangInstanceIdentifier path, final CompositeNode payload) { - this.checkPreconditions(); - - final DataModificationTransaction transaction = mountPoint.beginTransaction(); - /* check for available Node in Configuration DataStore by path */ - CompositeNode availableNode = transaction.readConfigurationData(path); - if (availableNode != null) { - String errMsg = "Post Configuration via Restconf was not executed because data already exists"; - BrokerFacade.LOG.warn((new StringBuilder(errMsg)).append(" : ").append(path).toString()); - - throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL, - ErrorTag.DATA_EXISTS); + return null; + } + + private CheckedFuture postDataViaTransaction( + final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore, + final YangInstanceIdentifier path, final NormalizedNode payload) { + ListenableFuture>> futureDatastoreData = rWTransaction.read(datastore, path); + try { + final Optional> optionalDatastoreData = futureDatastoreData.get(); + if (optionalDatastoreData.isPresent() && payload.equals(optionalDatastoreData.get())) { + String errMsg = "Post Configuration via Restconf was not executed because data already exists"; + LOG.trace(errMsg + ":{}", path); + throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL, + ErrorTag.DATA_EXISTS); + } + } catch (InterruptedException | ExecutionException e) { + LOG.trace("It wasn't possible to get data loaded from datastore at path " + path); } - BrokerFacade.LOG.trace("Post Configuration via Restconf: {}", path); - transaction.putConfigurationData(path, payload); - return transaction.commit(); - } - - public Future> commitConfigurationDataDelete(final YangInstanceIdentifier path) { - this.checkPreconditions(); - return deleteDataAtTarget(path, dataService.beginTransaction()); + rWTransaction.merge(datastore, path, payload); + LOG.trace("Post " + datastore.name() + " via Restconf: {}", path); + return rWTransaction.submit(); } - public Future> commitConfigurationDataDeleteBehindMountPoint( - final MountInstance mountPoint, final YangInstanceIdentifier path) { - this.checkPreconditions(); - return deleteDataAtTarget(path, mountPoint.beginTransaction()); + private CheckedFuture putDataViaTransaction( + final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore, + final YangInstanceIdentifier path, final NormalizedNode payload) { + LOG.trace("Put " + datastore.name() + " via Restconf: {}", path); + writeTransaction.put(datastore, path, payload); + return writeTransaction.submit(); } - private Future> deleteDataAtTarget(final YangInstanceIdentifier path, - final DataModificationTransaction transaction) { - LOG.info("Delete Configuration via Restconf: {}", path); - CompositeNode redDataAtPath = transaction.readConfigurationData(path); - if (redDataAtPath == null) { - return Futures.immediateFuture(RpcResultBuilder. - success(TransactionStatus.COMMITED).build()); - } - transaction.removeConfigurationData(path); - return transaction.commit(); + private CheckedFuture deleteDataViaTransaction( + final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore, + YangInstanceIdentifier path) { + LOG.info("Delete " + datastore.name() + " via Restconf: {}", path); + writeTransaction.delete(datastore, path); + return writeTransaction.submit(); } - public void registerToListenDataChanges(final ListenerAdapter listener) { - this.checkPreconditions(); - - if (listener.isListening()) { - return; - } - - YangInstanceIdentifier path = listener.getPath(); - final ListenerRegistration registration = dataService.registerDataChangeListener(path, - listener); - - listener.setRegistration(registration); + public void setDomDataBroker(DOMDataBroker domDataBroker) { + this.domDataBroker = domDataBroker; } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java index dad7a2cda2..6db4e63d10 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.restconf.impl; import com.google.common.base.Function; import com.google.common.base.Objects; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Splitter; @@ -17,7 +18,6 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; - import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; @@ -31,11 +31,9 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; - import javax.ws.rs.core.Response.Status; - -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.core.api.mount.MountService; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.impl.RestUtil; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; @@ -91,13 +89,13 @@ public class ControllerContext implements SchemaContextListener { new AtomicReference<>(Collections.emptyMap()); private volatile SchemaContext globalSchema; - private volatile MountService mountService; + private volatile DOMMountPointService mountService; public void setGlobalSchema(final SchemaContext globalSchema) { this.globalSchema = globalSchema; } - public void setMountService(final MountService mountService) { + public void setMountService(final DOMMountPointService mountService) { this.mountService = mountService; } @@ -207,7 +205,7 @@ public class ControllerContext implements SchemaContextListener { return this.getLatestModule(globalSchema, moduleName); } - public Module findModuleByName(final MountInstance mountPoint, final String moduleName) { + public Module findModuleByName(final DOMMountPoint mountPoint, final String moduleName) { Preconditions.checkArgument(moduleName != null && mountPoint != null); final SchemaContext mountPointSchema = mountPoint.getSchemaContext(); @@ -222,7 +220,7 @@ public class ControllerContext implements SchemaContextListener { return moduleSchemas == null ? null : this.filterLatestModule(moduleSchemas); } - public Module findModuleByNamespace(final MountInstance mountPoint, final URI namespace) { + public Module findModuleByNamespace(final DOMMountPoint mountPoint, final URI namespace) { Preconditions.checkArgument(namespace != null && mountPoint != null); final SchemaContext mountPointSchema = mountPoint.getSchemaContext(); @@ -237,7 +235,7 @@ public class ControllerContext implements SchemaContextListener { return globalSchema.findModuleByName(module.getLocalName(), module.getRevision()); } - public Module findModuleByNameAndRevision(final MountInstance mountPoint, final QName module) { + public Module findModuleByNameAndRevision(final DOMMountPoint mountPoint, final QName module) { this.checkPreconditions(); Preconditions.checkArgument(module != null && module.getLocalName() != null && module.getRevision() != null && mountPoint != null); @@ -306,7 +304,7 @@ public class ControllerContext implements SchemaContextListener { return moduleName; } - public String findModuleNameByNamespace(final MountInstance mountPoint, final URI namespace) { + public String findModuleNameByNamespace(final DOMMountPoint mountPoint, final URI namespace) { final Module module = this.findModuleByNamespace(mountPoint, namespace); return module == null ? null : module.getName(); } @@ -324,12 +322,12 @@ public class ControllerContext implements SchemaContextListener { return namespace; } - public URI findNamespaceByModuleName(final MountInstance mountPoint, final String moduleName) { + public URI findNamespaceByModuleName(final DOMMountPoint mountPoint, final String moduleName) { final Module module = this.findModuleByName(mountPoint, moduleName); return module == null ? null : module.getNamespace(); } - public Set getAllModules(final MountInstance mountPoint) { + public Set getAllModules(final DOMMountPoint mountPoint) { this.checkPreconditions(); SchemaContext schemaContext = mountPoint == null ? null : mountPoint.getSchemaContext(); @@ -363,7 +361,7 @@ public class ControllerContext implements SchemaContextListener { return builder.toString(); } - public CharSequence toRestconfIdentifier(final MountInstance mountPoint, final QName qname) { + public CharSequence toRestconfIdentifier(final DOMMountPoint mountPoint, final QName qname) { if (mountPoint == null) { return null; } @@ -525,7 +523,7 @@ public class ControllerContext implements SchemaContextListener { } private InstanceIdWithSchemaNode collectPathArguments(final InstanceIdentifierBuilder builder, - final List strings, final DataNodeContainer parentNode, final MountInstance mountPoint, + final List strings, final DataNodeContainer parentNode, final DOMMountPoint mountPoint, final boolean returnJustMountPoint) { Preconditions.> checkNotNull(strings); @@ -557,12 +555,13 @@ public class ControllerContext implements SchemaContextListener { } final YangInstanceIdentifier partialPath = builder.toInstance(); - final MountInstance mount = mountService.getMountPoint(partialPath); - if (mount == null) { + final Optional mountOpt = mountService.getMountPoint(partialPath); + if (!mountOpt.isPresent()) { LOG.debug("Instance identifier to missing mount point: {}", partialPath); throw new RestconfDocumentedException("Mount point does not exist.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); } + DOMMountPoint mount = mountOpt.get(); final SchemaContext mountPointSchema = mount.getSchemaContext(); if (mountPointSchema == null) { @@ -764,7 +763,7 @@ public class ControllerContext implements SchemaContextListener { } private void addKeyValue(final HashMap map, final DataSchemaNode node, final String uriValue, - final MountInstance mountPoint) { + final DOMMountPoint mountPoint) { Preconditions. checkNotNull(uriValue); Preconditions.checkArgument((node instanceof LeafSchemaNode)); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/InstanceIdWithSchemaNode.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/InstanceIdWithSchemaNode.java index 12c1ba66ec..b58a6eeaea 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/InstanceIdWithSchemaNode.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/InstanceIdWithSchemaNode.java @@ -7,7 +7,7 @@ */ package org.opendaylight.controller.sal.restconf.impl; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; @@ -15,10 +15,10 @@ public class InstanceIdWithSchemaNode { private final YangInstanceIdentifier instanceIdentifier; private final DataSchemaNode schemaNode; - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; public InstanceIdWithSchemaNode(YangInstanceIdentifier instanceIdentifier, DataSchemaNode schemaNode, - MountInstance mountPoint) { + DOMMountPoint mountPoint) { this.instanceIdentifier = instanceIdentifier; this.schemaNode = schemaNode; this.mountPoint = mountPoint; @@ -32,7 +32,7 @@ public class InstanceIdWithSchemaNode { return schemaNode; } - public MountInstance getMountPoint() { + public DOMMountPoint getMountPoint() { return mountPoint; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java index ff90dd8439..d61ccfdacf 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java @@ -12,7 +12,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.sal.rest.impl.RestUtil; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.Predicate; @@ -47,7 +47,7 @@ public class RestCodec { } public static final Codec from(final TypeDefinition typeDefinition, - final MountInstance mountPoint) { + final DOMMountPoint mountPoint) { return new ObjectCodec(typeDefinition, mountPoint); } @@ -62,7 +62,7 @@ public class RestCodec { private final TypeDefinition type; - private ObjectCodec(final TypeDefinition typeDefinition, final MountInstance mountPoint) { + private ObjectCodec(final TypeDefinition typeDefinition, final DOMMountPoint mountPoint) { type = RestUtil.resolveBaseTypeFrom(typeDefinition); if (type instanceof IdentityrefTypeDefinition) { identityrefCodec = new IdentityrefCodecImpl(mountPoint); @@ -158,9 +158,9 @@ public class RestCodec { private final Logger logger = LoggerFactory.getLogger(IdentityrefCodecImpl.class); - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; - public IdentityrefCodecImpl(final MountInstance mountPoint) { + public IdentityrefCodecImpl(final DOMMountPoint mountPoint) { this.mountPoint = mountPoint; } @@ -200,9 +200,9 @@ public class RestCodec { public static class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { private final Logger logger = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class); - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; - public InstanceIdentifierCodecImpl(final MountInstance mountPoint) { + public InstanceIdentifierCodecImpl(final DOMMountPoint mountPoint) { this.mountPoint = mountPoint; } @@ -318,7 +318,7 @@ public class RestCodec { } } - private static Module getModuleByNamespace(final String namespace, final MountInstance mountPoint) { + private static Module getModuleByNamespace(final String namespace, final DOMMountPoint mountPoint) { URI validNamespace = resolveValidNamespace(namespace, mountPoint); Module module = null; @@ -334,7 +334,7 @@ public class RestCodec { return module; } - private static URI resolveValidNamespace(final String namespace, final MountInstance mountPoint) { + private static URI resolveValidNamespace(final String namespace, final DOMMountPoint mountPoint) { URI validNamespace; if (mountPoint != null) { validNamespace = ControllerContext.getInstance().findNamespaceByModuleName(mountPoint, namespace); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java index 4c005c6ae5..b68bee2f0c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java @@ -24,17 +24,19 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.Future; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import org.apache.commons.lang3.StringUtils; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.api.RestconfService; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; @@ -47,16 +49,23 @@ import org.opendaylight.controller.sal.streams.listeners.Notificator; import org.opendaylight.controller.sal.streams.websockets.WebSocketServer; import org.opendaylight.yangtools.concepts.Codec; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder; 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.MutableCompositeNode; -import org.opendaylight.yangtools.yang.data.api.Node; -import org.opendaylight.yangtools.yang.data.api.SimpleNode; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +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.composite.node.schema.cnsn.parser.CnSnToNormalizedNodeParserFactory; +import org.opendaylight.yangtools.yang.data.composite.node.schema.cnsn.serializer.CnSnFromNormalizedNodeSerializerFactory; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; @@ -76,6 +85,8 @@ import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; import org.opendaylight.yangtools.yang.model.util.EmptyType; import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class RestconfImpl implements RestconfService { private enum UriParameters { @@ -96,6 +107,8 @@ public class RestconfImpl implements RestconfService { private final static RestconfImpl INSTANCE = new RestconfImpl(); + private static final int NOTIFICATION_PORT = 8181; + private static final int CHAR_NOT_FOUND = -1; private final static String MOUNT_POINT_MODULE_NAME = "ietf-netconf"; @@ -110,6 +123,30 @@ public class RestconfImpl implements RestconfService { private ControllerContext controllerContext; + private static final Logger LOG = LoggerFactory.getLogger(RestconfImpl.class); + + private static final DataChangeScope DEFAULT_SCOPE = DataChangeScope.BASE; + + private static final LogicalDatastoreType DEFAULT_DATASTORE = LogicalDatastoreType.CONFIGURATION; + + private static final URI NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT = URI.create("urn:sal:restconf:event:subscription"); + + private static final Date EVENT_SUBSCRIPTION_AUGMENT_REVISION; + + private static final String DATASTORE_PARAM_NAME = "datastore"; + + private static final String SCOPE_PARAM_NAME = "scope"; + + static { + try { + EVENT_SUBSCRIPTION_AUGMENT_REVISION = new SimpleDateFormat("yyyy-MM-dd").parse("2014-07-08"); + } catch (ParseException e) { + throw new RestconfDocumentedException( + "It wasn't possible to convert revision date of sal-remote-augment to date", ErrorType.APPLICATION, + ErrorTag.OPERATION_FAILED); + } + } + public void setBroker(final BrokerFacade broker) { this.broker = broker; } @@ -168,7 +205,7 @@ public class RestconfImpl implements RestconfService { @Override public StructuredData getModules(final String identifier, final UriInfo uriInfo) { Set modules = null; - MountInstance mountPoint = null; + DOMMountPoint mountPoint = null; if (identifier.contains(ControllerContext.MOUNT)) { InstanceIdWithSchemaNode mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier); mountPoint = mountPointIdentifier.getMountPoint(); @@ -199,7 +236,7 @@ public class RestconfImpl implements RestconfService { public StructuredData getModule(final String identifier, final UriInfo uriInfo) { final QName moduleNameAndRevision = this.getModuleNameAndRevision(identifier); Module module = null; - MountInstance mountPoint = null; + DOMMountPoint mountPoint = null; if (identifier.contains(ControllerContext.MOUNT)) { InstanceIdWithSchemaNode mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier); mountPoint = mountPointIdentifier.getMountPoint(); @@ -230,7 +267,7 @@ public class RestconfImpl implements RestconfService { @Override public StructuredData getOperations(final String identifier, final UriInfo uriInfo) { Set modules = null; - MountInstance mountPoint = null; + DOMMountPoint mountPoint = null; if (identifier.contains(ControllerContext.MOUNT)) { InstanceIdWithSchemaNode mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier); mountPoint = mountPointIdentifier.getMountPoint(); @@ -245,7 +282,7 @@ public class RestconfImpl implements RestconfService { } private StructuredData operationsFromModulesToStructuredData(final Set modules, - final MountInstance mountPoint, boolean prettyPrint) { + final DOMMountPoint mountPoint, boolean prettyPrint) { final List> operationsAsData = new ArrayList>(); Module restconfModule = this.getRestconfModule(); final DataSchemaNode operationsSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode( @@ -405,7 +442,7 @@ public class RestconfImpl implements RestconfService { return callRpc(rpc, payload, parsePrettyPrintParameter(uriInfo)); } - private void validateInput(final DataSchemaNode inputSchema, final CompositeNode payload) { + private void validateInput(final DataSchemaNode inputSchema, final Node payload) { if (inputSchema != null && payload == null) { // expected a non null payload throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE); @@ -416,6 +453,7 @@ public class RestconfImpl implements RestconfService { // else // { // TODO: Validate "mandatory" and "config" values here??? Or should those be + // those be // validate in a more central location inside MD-SAL core. // } } @@ -436,7 +474,15 @@ public class RestconfImpl implements RestconfService { String streamName = null; if (!Iterables.isEmpty(pathIdentifier.getPathArguments())) { String fullRestconfIdentifier = this.controllerContext.toFullRestconfIdentifier(pathIdentifier); - streamName = Notificator.createStreamNameFromUri(fullRestconfIdentifier); + + LogicalDatastoreType datastore = parseEnumTypeParameter(value, LogicalDatastoreType.class, DATASTORE_PARAM_NAME); + datastore = datastore == null ? DEFAULT_DATASTORE : datastore; + + DataChangeScope scope = parseEnumTypeParameter(value, DataChangeScope.class, SCOPE_PARAM_NAME); + scope = scope == null ? DEFAULT_SCOPE : scope; + + streamName = Notificator.createStreamNameFromUri(fullRestconfIdentifier + "/datastore=" + datastore + + "/scope=" + scope); } if (Strings.isNullOrEmpty(streamName)) { @@ -453,7 +499,7 @@ public class RestconfImpl implements RestconfService { final MutableCompositeNode responseData = NodeFactory.createMutableCompositeNode(rpc.getOutput().getQName(), null, output, null, null); - if (!Notificator.existListenerFor(pathIdentifier)) { + if (!Notificator.existListenerFor(streamName)) { Notificator.createListener(pathIdentifier, streamName); } @@ -470,7 +516,7 @@ public class RestconfImpl implements RestconfService { private RpcExecutor resolveIdentifierInInvokeRpc(final String identifier) { String identifierEncoded = null; - MountInstance mountPoint = null; + DOMMountPoint mountPoint = null; if (identifier.contains(ControllerContext.MOUNT)) { // mounted RPC call - look up mount instance. InstanceIdWithSchemaNode mountPointId = controllerContext.toMountPointIdentifier(identifier); @@ -582,18 +628,20 @@ public class RestconfImpl implements RestconfService { @Override public StructuredData readConfigurationData(final String identifier, final UriInfo uriInfo) { - final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier); - CompositeNode data = null; - MountInstance mountPoint = iiWithData.getMountPoint(); + final InstanceIdWithSchemaNode iiWithData = normalizeInstanceIdentifierWithSchemaNode( + this.controllerContext.toInstanceIdentifier(identifier), true); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); + NormalizedNode data = null; if (mountPoint != null) { - data = broker.readConfigurationDataBehindMountPoint(mountPoint, iiWithData.getInstanceIdentifier()); + data = broker.readConfigurationData(mountPoint, iiWithData.getInstanceIdentifier()); } else { data = broker.readConfigurationData(iiWithData.getInstanceIdentifier()); } + CompositeNode compositeNode = datastoreNormalizedNodeToCompositeNode(data, iiWithData.getSchemaNode()); - data = pruneDataAtDepth(data, parseDepthParameter(uriInfo)); + compositeNode = pruneDataAtDepth(compositeNode, parseDepthParameter(uriInfo)); boolean prettyPrintMode = parsePrettyPrintParameter(uriInfo); - return new StructuredData(data, iiWithData.getSchemaNode(), iiWithData.getMountPoint(), prettyPrintMode); + return new StructuredData(compositeNode, iiWithData.getSchemaNode(), iiWithData.getMountPoint(), prettyPrintMode); } @SuppressWarnings("unchecked") @@ -640,18 +688,21 @@ public class RestconfImpl implements RestconfService { @Override public StructuredData readOperationalData(final String identifier, final UriInfo info) { - final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier); - CompositeNode data = null; - MountInstance mountPoint = iiWithData.getMountPoint(); + final InstanceIdWithSchemaNode iiWithData = normalizeInstanceIdentifierWithSchemaNode( + this.controllerContext.toInstanceIdentifier(identifier), true); + NormalizedNode data = null; + + DOMMountPoint mountPoint = iiWithData.getMountPoint(); if (mountPoint != null) { - data = broker.readOperationalDataBehindMountPoint(mountPoint, iiWithData.getInstanceIdentifier()); + data = broker.readOperationalData(mountPoint, iiWithData.getInstanceIdentifier()); } else { data = broker.readOperationalData(iiWithData.getInstanceIdentifier()); } - data = pruneDataAtDepth(data, parseDepthParameter(info)); - boolean prettyPrintMode = parsePrettyPrintParameter(info); - return new StructuredData(data, iiWithData.getSchemaNode(), mountPoint, prettyPrintMode); + final CompositeNode compositeNode = datastoreNormalizedNodeToCompositeNode(data, iiWithData.getSchemaNode()); + final CompositeNode prunedCompositeNode = pruneDataAtDepth(compositeNode, parseDepthParameter(info)); + final boolean prettyPrintMode = parsePrettyPrintParameter(info); + return new StructuredData(prunedCompositeNode, iiWithData.getSchemaNode(), mountPoint,prettyPrintMode); } private boolean parsePrettyPrintParameter(UriInfo info) { @@ -660,32 +711,31 @@ public class RestconfImpl implements RestconfService { } @Override - public Response updateConfigurationData(final String identifier, final CompositeNode payload) { - final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier); + public Response updateConfigurationData(final String identifier, final Node payload) { + final InstanceIdWithSchemaNode iiWithData = normalizeInstanceIdentifierWithSchemaNode(this.controllerContext + .toInstanceIdentifier(identifier)); validateInput(iiWithData.getSchemaNode(), payload); - MountInstance mountPoint = iiWithData.getMountPoint(); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); final CompositeNode value = this.normalizeNode(payload, iiWithData.getSchemaNode(), mountPoint); - validateListKeysEqualityInPayloadAndUri(iiWithData, payload); - RpcResult status = null; + validateListKeysEqualityInPayloadAndUri(iiWithData, value); + final NormalizedNode datastoreNormalizedNode = compositeNodeToDatastoreNormalizedNode(value, + iiWithData.getSchemaNode()); try { if (mountPoint != null) { - status = broker.commitConfigurationDataPutBehindMountPoint(mountPoint, - iiWithData.getInstanceIdentifier(), value).get(); + broker.commitConfigurationDataPut(mountPoint, iiWithData.getInstanceIdentifier(), + datastoreNormalizedNode).get(); } else { - status = broker.commitConfigurationDataPut(iiWithData.getInstanceIdentifier(), value).get(); + broker.commitConfigurationDataPut(iiWithData.getInstanceIdentifier(), datastoreNormalizedNode) + .get(); } } catch (Exception e) { throw new RestconfDocumentedException("Error updating data", e); } - if (status.getResult() == TransactionStatus.COMMITED) { - return Response.status(Status.OK).build(); - } - - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + return Response.status(Status.OK).build(); } /** @@ -734,7 +784,7 @@ public class RestconfImpl implements RestconfService { } @Override - public Response createConfigurationData(final String identifier, final CompositeNode payload) { + public Response createConfigurationData(final String identifier, final Node payload) { if (payload == null) { throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE); } @@ -765,8 +815,8 @@ public class RestconfImpl implements RestconfService { final InstanceIdWithSchemaNode incompleteInstIdWithData = this.controllerContext .toInstanceIdentifier(identifier); final DataNodeContainer parentSchema = (DataNodeContainer) incompleteInstIdWithData.getSchemaNode(); - MountInstance mountPoint = incompleteInstIdWithData.getMountPoint(); - final Module module = this.findModule(mountPoint, payload); + DOMMountPoint mountPoint = incompleteInstIdWithData.getMountPoint(); + final Module module = findModule(mountPoint, payload); if (module == null) { throw new RestconfDocumentedException("Module was not found for \"" + payloadNS + "\"", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); @@ -777,38 +827,30 @@ public class RestconfImpl implements RestconfService { parentSchema, payloadName, module.getNamespace()); value = this.normalizeNode(payload, schemaNode, mountPoint); - iiWithData = this.addLastIdentifierFromData(incompleteInstIdWithData, value, schemaNode); + iiWithData = normalizeInstanceIdentifierWithSchemaNode(this.addLastIdentifierFromData( + incompleteInstIdWithData, value, schemaNode)); } - RpcResult status = null; - MountInstance mountPoint = iiWithData.getMountPoint(); + final NormalizedNode datastoreNormalizedData = compositeNodeToDatastoreNormalizedNode(value, + iiWithData.getSchemaNode()); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); try { if (mountPoint != null) { - Future> future = broker.commitConfigurationDataPostBehindMountPoint( - mountPoint, iiWithData.getInstanceIdentifier(), value); - status = future == null ? null : future.get(); + broker.commitConfigurationDataPost(mountPoint, + iiWithData.getInstanceIdentifier(), datastoreNormalizedData); } else { - Future> future = broker.commitConfigurationDataPost( - iiWithData.getInstanceIdentifier(), value); - status = future == null ? null : future.get(); + broker.commitConfigurationDataPost( + iiWithData.getInstanceIdentifier(), datastoreNormalizedData); } } catch (Exception e) { throw new RestconfDocumentedException("Error creating data", e); } - if (status == null) { - return Response.status(Status.ACCEPTED).build(); - } - - if (status.getResult() == TransactionStatus.COMMITED) { - return Response.status(Status.NO_CONTENT).build(); - } - - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + return Response.status(Status.NO_CONTENT).build(); } @Override - public Response createConfigurationData(final CompositeNode payload) { + public Response createConfigurationData(final Node payload) { if (payload == null) { throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE); } @@ -833,57 +875,56 @@ public class RestconfImpl implements RestconfService { final CompositeNode value = this.normalizeNode(payload, schemaNode, null); final InstanceIdWithSchemaNode iiWithData = this.addLastIdentifierFromData(null, value, schemaNode); RpcResult status = null; - MountInstance mountPoint = iiWithData.getMountPoint(); + final NormalizedNode datastoreNormalizedData = compositeNodeToDatastoreNormalizedNode(value, schemaNode); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); try { if (mountPoint != null) { - Future> future = broker.commitConfigurationDataPostBehindMountPoint( - mountPoint, iiWithData.getInstanceIdentifier(), value); - status = future == null ? null : future.get(); + broker.commitConfigurationDataPost(mountPoint, + iiWithData.getInstanceIdentifier(), datastoreNormalizedData); } else { - Future> future = broker.commitConfigurationDataPost( - iiWithData.getInstanceIdentifier(), value); - status = future == null ? null : future.get(); + broker.commitConfigurationDataPost( + iiWithData.getInstanceIdentifier(), datastoreNormalizedData); } } catch (Exception e) { throw new RestconfDocumentedException("Error creating data", e); } - if (status == null) { - return Response.status(Status.ACCEPTED).build(); - } - - if (status.getResult() == TransactionStatus.COMMITED) { - return Response.status(Status.NO_CONTENT).build(); - } - - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + return Response.status(Status.NO_CONTENT).build(); } @Override public Response deleteConfigurationData(final String identifier) { - final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier); + final InstanceIdWithSchemaNode iiWithData = normalizeInstanceIdentifierWithSchemaNode(this.controllerContext + .toInstanceIdentifier(identifier)); RpcResult status = null; - MountInstance mountPoint = iiWithData.getMountPoint(); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); try { if (mountPoint != null) { - status = broker.commitConfigurationDataDeleteBehindMountPoint(mountPoint, - iiWithData.getInstanceIdentifier()).get(); + broker.commitConfigurationDataDelete(mountPoint, iiWithData.getInstanceIdentifier()).get(); } else { - status = broker.commitConfigurationDataDelete(iiWithData.getInstanceIdentifier()).get(); + broker.commitConfigurationDataDelete(iiWithData.getInstanceIdentifier()).get(); } } catch (Exception e) { throw new RestconfDocumentedException("Error creating data", e); } - if (status.getResult() == TransactionStatus.COMMITED) { - return Response.status(Status.OK).build(); - } - - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + return Response.status(Status.OK).build(); } + /** + * Subscribes to some path in schema context (stream) to listen on changes + * on this stream. + * + * Additional parameters for subscribing to stream are loaded via rpc input + * parameters: + *
    + *
  • datastore
  • - default CONFIGURATION (other values of + * {@link LogicalDatastoreType} enum type) + *
  • scope
  • - default BASE (other values of {@link DataChangeScope}) + *
+ */ @Override public Response subscribeToStream(final String identifier, final UriInfo uriInfo) { final String streamName = Notificator.createStreamNameFromUri(identifier); @@ -896,18 +937,100 @@ public class RestconfImpl implements RestconfService { throw new RestconfDocumentedException("Stream was not found.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); } - broker.registerToListenDataChanges(listener); + Map paramToValues = resolveValuesFromUri(identifier); + 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); + } + DataChangeScope scope = parserURIEnumParameter(DataChangeScope.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(); - UriBuilder port = uriBuilder.port(WebSocketServer.getInstance().getPort()); + int notificationPort = NOTIFICATION_PORT; + try { + WebSocketServer webSocketServerInstance = WebSocketServer.getInstance(); + notificationPort = webSocketServerInstance.getPort(); + } catch (NullPointerException e) { + WebSocketServer.createInstance(NOTIFICATION_PORT); + } + UriBuilder port = uriBuilder.port(notificationPort); final URI uriToWebsocketServer = port.replacePath(streamName).build(); return Response.status(Status.OK).location(uriToWebsocketServer).build(); } - private Module findModule(final MountInstance mountPoint, final CompositeNode data) { - if (data instanceof CompositeNodeWrapper) { - return findModule(mountPoint, (CompositeNodeWrapper) data); + /** + * Load parameter for subscribing to stream from input composite node + * + * @param compNode + * contains value + * @return enum object if its string value is equal to {@code paramName}. In + * other cases null. + */ + private T parseEnumTypeParameter(final CompositeNode compNode, final Class classDescriptor, + final String paramName) { + QNameModule salRemoteAugment = QNameModule.create(NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT, + EVENT_SUBSCRIPTION_AUGMENT_REVISION); + SimpleNode simpleNode = compNode.getFirstSimpleByName(QName.create(salRemoteAugment, paramName)); + if (simpleNode == null) { + return null; + } + Object rawValue = simpleNode.getValue(); + 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 T parserURIEnumParameter(final Class classDescriptor, final String value) { + if (Strings.isNullOrEmpty(value)) { + return null; + } + return resolveAsEnum(classDescriptor, value); + } + + private T resolveAsEnum(Class classDescriptor, String value) { + T[] enumConstants = classDescriptor.getEnumConstants(); + if (enumConstants != null) { + for (T enm : classDescriptor.getEnumConstants()) { + if (((Enum) enm).name().equals(value)) { + return enm; + } + } + } + return null; + } + + private Map resolveValuesFromUri(String uri) { + Map result = new HashMap<>(); + String[] tokens = uri.split("/"); + for (int i = 1; i < tokens.length; i++) { + String[] parameterTokens = tokens[i].split("="); + if (parameterTokens.length == 2) { + result.put(parameterTokens[0], parameterTokens[1]); + } + } + return result; + } + + private Module findModule(final DOMMountPoint mountPoint, final Node data) { + if (data instanceof NodeWrapper) { + return findModule(mountPoint, (NodeWrapper) data); } else if (data != null) { URI namespace = data.getNodeType().getNamespace(); if (mountPoint != null) { @@ -921,7 +1044,7 @@ public class RestconfImpl implements RestconfService { } } - private Module findModule(final MountInstance mountPoint, final CompositeNodeWrapper data) { + private Module findModule(final DOMMountPoint mountPoint, final NodeWrapper data) { URI namespace = data.getNamespace(); Preconditions. checkNotNull(namespace); @@ -956,15 +1079,10 @@ public class RestconfImpl implements RestconfService { iiBuilder = YangInstanceIdentifier.builder(iiOriginal); } - if ((schemaOfData instanceof ListSchemaNode)) { - HashMap keys = this.resolveKeysFromData(((ListSchemaNode) schemaOfData), data); - iiBuilder.nodeWithKey(schemaOfData.getQName(), keys); - } else { - iiBuilder.node(schemaOfData.getQName()); - } + iiBuilder.node(schemaOfData.getQName()); YangInstanceIdentifier instance = iiBuilder.toInstance(); - MountInstance mountPoint = null; + DOMMountPoint mountPoint = null; if (identifierWithSchemaNode != null) { mountPoint = identifierWithSchemaNode.getMountPoint(); } @@ -1004,7 +1122,7 @@ public class RestconfImpl implements RestconfService { return identifier.endsWith(ControllerContext.MOUNT) || identifier.endsWith(ControllerContext.MOUNT + "/"); } - private boolean representsMountPointRootData(final CompositeNode data) { + private boolean representsMountPointRootData(final Node data) { URI namespace = this.namespace(data); return (SchemaContext.NAME.getNamespace().equals(namespace) /* * || MOUNT_POINT_MODULE_NAME .equals( namespace . @@ -1022,8 +1140,7 @@ public class RestconfImpl implements RestconfService { return identifier + "/" + ControllerContext.MOUNT; } - private CompositeNode normalizeNode(final CompositeNode node, final DataSchemaNode schema, - final MountInstance mountPoint) { + private CompositeNode normalizeNode(final Node node, final DataSchemaNode schema, final DOMMountPoint mountPoint) { if (schema == null) { QName nodeType = node == null ? null : node.getNodeType(); String localName = nodeType == null ? null : nodeType.getLocalName(); @@ -1037,24 +1154,32 @@ public class RestconfImpl implements RestconfService { ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); } - if ((node instanceof CompositeNodeWrapper)) { - boolean isChangeAllowed = ((CompositeNodeWrapper) node).isChangeAllowed(); + if ((node instanceof NodeWrapper)) { + NodeWrapper nodeWrap = (NodeWrapper) node; + boolean isChangeAllowed = ((NodeWrapper) node).isChangeAllowed(); if (isChangeAllowed) { + nodeWrap = topLevelElementAsCompositeNodeWrapper((NodeWrapper) node, schema); try { - this.normalizeNode(((CompositeNodeWrapper) node), schema, null, mountPoint); + this.normalizeNode(nodeWrap, schema, null, mountPoint); } catch (IllegalArgumentException e) { throw new RestconfDocumentedException(e.getMessage(), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); } + if (nodeWrap instanceof CompositeNodeWrapper) { + return ((CompositeNodeWrapper) nodeWrap).unwrap(); + } } + } - return ((CompositeNodeWrapper) node).unwrap(); + if (node instanceof CompositeNode) { + return (CompositeNode) node; } - return node; + throw new RestconfDocumentedException("Top level element is not interpreted as composite node.", + ErrorType.APPLICATION, ErrorTag.INVALID_VALUE); } private void normalizeNode(final NodeWrapper nodeBuilder, final DataSchemaNode schema, - final QName previousAugment, final MountInstance mountPoint) { + final QName previousAugment, final DOMMountPoint mountPoint) { if (schema == null) { throw new RestconfDocumentedException("Data has bad format.\n\"" + nodeBuilder.getLocalName() + "\" does not exist in yang schema.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); @@ -1111,7 +1236,7 @@ public class RestconfImpl implements RestconfService { } private void normalizeSimpleNode(final SimpleNodeWrapper simpleNode, final DataSchemaNode schema, - final MountInstance mountPoint) { + final DOMMountPoint mountPoint) { final Object value = simpleNode.getValue(); Object inputValue = value; TypeDefinition typeDefinition = this.typeDefinition(schema); @@ -1133,7 +1258,7 @@ public class RestconfImpl implements RestconfService { } private void normalizeCompositeNode(final CompositeNodeWrapper compositeNodeBuilder, - final DataNodeContainer schema, final MountInstance mountPoint, final QName currentAugment) { + final DataNodeContainer schema, final DOMMountPoint mountPoint, final QName currentAugment) { final List> children = compositeNodeBuilder.getValues(); checkNodeMultiplicityAccordingToSchema(schema, children); for (final NodeWrapper child : children) { @@ -1214,7 +1339,7 @@ public class RestconfImpl implements RestconfService { } private QName normalizeNodeName(final NodeWrapper nodeBuilder, final DataSchemaNode schema, - final QName previousAugment, final MountInstance mountPoint) { + final QName previousAugment, final DOMMountPoint mountPoint) { QName validQName = schema.getQName(); QName currentAugment = previousAugment; if (schema.isAugmenting()) { @@ -1248,9 +1373,9 @@ public class RestconfImpl implements RestconfService { return currentAugment; } - private URI namespace(final CompositeNode data) { - if (data instanceof CompositeNodeWrapper) { - return ((CompositeNodeWrapper) data).getNamespace(); + private URI namespace(final Node data) { + if (data instanceof NodeWrapper) { + return ((NodeWrapper) data).getNamespace(); } else if (data != null) { return data.getNodeType().getNamespace(); } else { @@ -1258,9 +1383,9 @@ public class RestconfImpl implements RestconfService { } } - private String localName(final CompositeNode data) { - if (data instanceof CompositeNodeWrapper) { - return ((CompositeNodeWrapper) data).getLocalName(); + private String localName(final Node data) { + if (data instanceof NodeWrapper) { + return ((NodeWrapper) data).getLocalName(); } else if (data != null) { return data.getNodeType().getLocalName(); } else { @@ -1268,9 +1393,9 @@ public class RestconfImpl implements RestconfService { } } - private String getName(final CompositeNode data) { - if (data instanceof CompositeNodeWrapper) { - return ((CompositeNodeWrapper) data).getLocalName(); + private String getName(final Node data) { + if (data instanceof NodeWrapper) { + return ((NodeWrapper) data).getLocalName(); } else if (data != null) { return data.getNodeType().getLocalName(); } else { @@ -1307,4 +1432,99 @@ public class RestconfImpl implements RestconfService { throw new IllegalArgumentException("Unhandled parameter types: " + Arrays. asList(node).toString()); } } + + private CompositeNode datastoreNormalizedNodeToCompositeNode(NormalizedNode dataNode, DataSchemaNode schema) { + Iterable> nodes = null; + if (dataNode == null) { + throw new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION, ErrorTag.DATA_MISSING, + "No data was found.")); + } + if (schema instanceof ContainerSchemaNode && dataNode instanceof ContainerNode) { + nodes = CnSnFromNormalizedNodeSerializerFactory.getInstance().getContainerNodeSerializer() + .serialize((ContainerSchemaNode) schema, (ContainerNode) dataNode); + } else if (schema instanceof ListSchemaNode && dataNode instanceof MapNode) { + nodes = CnSnFromNormalizedNodeSerializerFactory.getInstance().getMapNodeSerializer() + .serialize((ListSchemaNode) schema, (MapNode) dataNode); + } else if (schema instanceof ListSchemaNode && dataNode instanceof MapEntryNode) { + nodes = CnSnFromNormalizedNodeSerializerFactory.getInstance().getMapEntryNodeSerializer() + .serialize((ListSchemaNode) schema, (MapEntryNode) dataNode); + } + if (nodes != null) { + if (nodes.iterator().hasNext()) { + Node nodeOldStruct = nodes.iterator().next(); + return (CompositeNode) nodeOldStruct; + } else { + LOG.error("The node " + dataNode.getNodeType() + " couldn't be transformed to compositenode."); + } + } else { + LOG.error("Top level node isn't of type Container or List schema node but " + + schema.getClass().getSimpleName()); + } + + throw new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "It wasn't possible to correctly interpret data.")); + } + + private NormalizedNode compositeNodeToDatastoreNormalizedNode(CompositeNode compNode, DataSchemaNode schema) { + List> lst = new ArrayList>(); + lst.add(compNode); + if (schema instanceof ContainerSchemaNode) { + return CnSnToNormalizedNodeParserFactory.getInstance().getContainerNodeParser() + .parse(lst, (ContainerSchemaNode) schema); + } else if (schema instanceof ListSchemaNode) { + return CnSnToNormalizedNodeParserFactory.getInstance().getMapNodeParser() + .parse(lst, (ListSchemaNode) schema); + } + + LOG.error("Top level isn't of type container, list, leaf schema node but " + schema.getClass().getSimpleName()); + + throw new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "It wasn't possible to translate specified data to datastore readable form.")); + } + + private InstanceIdWithSchemaNode normalizeInstanceIdentifierWithSchemaNode(InstanceIdWithSchemaNode iiWithSchemaNode) { + return normalizeInstanceIdentifierWithSchemaNode(iiWithSchemaNode, false); + } + + private InstanceIdWithSchemaNode normalizeInstanceIdentifierWithSchemaNode( + InstanceIdWithSchemaNode iiWithSchemaNode, boolean unwrapLastListNode) { + return new InstanceIdWithSchemaNode(instanceIdentifierToReadableFormForNormalizeNode( + iiWithSchemaNode.getInstanceIdentifier(), unwrapLastListNode), iiWithSchemaNode.getSchemaNode(), + iiWithSchemaNode.getMountPoint()); + } + + private YangInstanceIdentifier instanceIdentifierToReadableFormForNormalizeNode(YangInstanceIdentifier instIdentifier, + boolean unwrapLastListNode) { + Preconditions.checkNotNull(instIdentifier, "Instance identifier can't be null"); + final List result = new ArrayList(); + final Iterator iter = instIdentifier.getPathArguments().iterator(); + while (iter.hasNext()) { + final PathArgument pathArgument = iter.next(); + if (pathArgument instanceof NodeIdentifierWithPredicates && (iter.hasNext() || unwrapLastListNode)) { + result.add(new YangInstanceIdentifier.NodeIdentifier(pathArgument.getNodeType())); + } + result.add(pathArgument); + } + return YangInstanceIdentifier.create(result); + } + + private CompositeNodeWrapper topLevelElementAsCompositeNodeWrapper(final NodeWrapper node, + final DataSchemaNode schemaNode) { + if (node instanceof CompositeNodeWrapper) { + return (CompositeNodeWrapper) node; + } else if (node instanceof SimpleNodeWrapper && isDataContainerNode(schemaNode)) { + final SimpleNodeWrapper simpleNodeWrapper = (SimpleNodeWrapper) node; + return new CompositeNodeWrapper(namespace(simpleNodeWrapper), localName(simpleNodeWrapper)); + } + + throw new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "Top level element has to be composite node or has to represent data container node.")); + } + + private boolean isDataContainerNode(final DataSchemaNode schemaNode) { + if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode) { + return true; + } + return false; + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java index c745a8009d..2935434967 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java @@ -7,7 +7,7 @@ */ package org.opendaylight.controller.sal.restconf.impl; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; @@ -15,14 +15,14 @@ public class StructuredData { private final CompositeNode data; private final DataSchemaNode schema; - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; private final boolean prettyPrintMode; - public StructuredData(final CompositeNode data, final DataSchemaNode schema, final MountInstance mountPoint) { + public StructuredData(final CompositeNode data, final DataSchemaNode schema, final DOMMountPoint mountPoint) { this(data, schema, mountPoint, false); } - public StructuredData(final CompositeNode data, final DataSchemaNode schema, final MountInstance mountPoint, + public StructuredData(final CompositeNode data, final DataSchemaNode schema, final DOMMountPoint mountPoint, final boolean preattyPrintMode) { this.data = data; this.schema = schema; @@ -38,7 +38,7 @@ public class StructuredData { return schema; } - public MountInstance getMountPoint() { + public DOMMountPoint getMountPoint() { return mountPoint; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/rpc/impl/MountPointRpcExecutor.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/rpc/impl/MountPointRpcExecutor.java index 36502656c2..efb3e0a1d3 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/rpc/impl/MountPointRpcExecutor.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/rpc/impl/MountPointRpcExecutor.java @@ -7,9 +7,12 @@ */ package org.opendaylight.controller.sal.restconf.rpc.impl; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; import java.util.concurrent.Future; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; @@ -21,9 +24,9 @@ import org.opendaylight.yangtools.yang.model.api.RpcDefinition; * */ public class MountPointRpcExecutor extends AbstractRpcExecutor { - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; - public MountPointRpcExecutor(RpcDefinition rpcDef, MountInstance mountPoint) { + public MountPointRpcExecutor(RpcDefinition rpcDef, DOMMountPoint mountPoint) { super(rpcDef); this.mountPoint = mountPoint; Preconditions.checkNotNull(mountPoint, "MountInstance can not be null."); @@ -31,6 +34,10 @@ public class MountPointRpcExecutor extends AbstractRpcExecutor { @Override protected Future> invokeRpcUnchecked(CompositeNode rpcRequest) { - return mountPoint.rpc(getRpcDefinition().getQName(), rpcRequest); + Optional service = mountPoint.getService(RpcProvisionRegistry.class); + if (service.isPresent()) { + return service.get().invokeRpc(getRpcDefinition().getQName(), rpcRequest); + } + throw new RestconfDocumentedException("Rpc service is missing."); } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java index 2b7b0246e3..a6e02632ce 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java @@ -38,8 +38,8 @@ 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.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.core.api.data.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; import org.opendaylight.controller.sal.rest.impl.XmlMapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.yangtools.concepts.ListenerRegistration; @@ -49,6 +49,7 @@ 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.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,7 +60,7 @@ import org.w3c.dom.Node; /** * {@link ListenerAdapter} is responsible to track events, which occurred by changing data in data source. */ -public class ListenerAdapter implements DataChangeListener { +public class ListenerAdapter implements DOMDataChangeListener { private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapter.class); private static final DocumentBuilderFactory DBF = DocumentBuilderFactory.newInstance(); @@ -70,7 +71,7 @@ public class ListenerAdapter implements DataChangeListener { private final SimpleDateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssZ"); private final YangInstanceIdentifier path; - private ListenerRegistration registration; + private ListenerRegistration registration; private final String streamName; private Set subscribers = new ConcurrentSet<>(); private final EventBus eventBus; @@ -95,10 +96,11 @@ public class ListenerAdapter implements DataChangeListener { } @Override - public void onDataChanged(final DataChangeEvent change) { - if (!change.getCreatedConfigurationData().isEmpty() || !change.getCreatedOperationalData().isEmpty() - || !change.getUpdatedConfigurationData().isEmpty() || !change.getUpdatedOperationalData().isEmpty() - || !change.getRemovedConfigurationData().isEmpty() || !change.getRemovedOperationalData().isEmpty()) { + public void onDataChanged(AsyncDataChangeEvent> change) { + // TODO Auto-generated method stub + + if (!change.getCreatedData().isEmpty() || !change.getUpdatedData().isEmpty() + || !change.getRemovedPaths().isEmpty()) { String xml = prepareXmlFrom(change); Event event = new Event(EventType.NOTIFY); event.setData(xml); @@ -216,7 +218,7 @@ public class ListenerAdapter implements DataChangeListener { * DataChangeEvent * @return Data in printable form. */ - private String prepareXmlFrom(final DataChangeEvent change) { + private String prepareXmlFrom(AsyncDataChangeEvent> change) { Document doc = createDocument(); Element notificationElement = doc.createElementNS("urn:ietf:params:xml:ns:netconf:notification:1.0", "notification"); @@ -262,7 +264,6 @@ public class ListenerAdapter implements DataChangeListener { /** * Creates {@link Document} document. - * * @return {@link Document} document. */ private Document createDocument() { @@ -287,23 +288,15 @@ public class ListenerAdapter implements DataChangeListener { */ private void addValuesToDataChangedNotificationEventElement(final Document doc, final Element dataChangedNotificationEventElement, - final DataChangeEvent change) { - addValuesFromDataToElement(doc, change.getCreatedConfigurationData(), dataChangedNotificationEventElement, - Store.CONFIG, Operation.CREATED); - addValuesFromDataToElement(doc, change.getCreatedOperationalData(), dataChangedNotificationEventElement, - Store.OPERATION, Operation.CREATED); - if (change.getCreatedConfigurationData().isEmpty()) { - addValuesFromDataToElement(doc, change.getUpdatedConfigurationData(), dataChangedNotificationEventElement, - Store.CONFIG, Operation.UPDATED); - } - if (change.getCreatedOperationalData().isEmpty()) { - addValuesFromDataToElement(doc, change.getUpdatedOperationalData(), dataChangedNotificationEventElement, - Store.OPERATION, Operation.UPDATED); + AsyncDataChangeEvent> change) { + addValuesFromDataToElement(doc, change.getCreatedData().keySet(), dataChangedNotificationEventElement, + Operation.CREATED); + if (change.getCreatedData().isEmpty()) { + addValuesFromDataToElement(doc, change.getUpdatedData().keySet(), dataChangedNotificationEventElement, + Operation.UPDATED); } - addValuesFromDataToElement(doc, change.getRemovedConfigurationData(), dataChangedNotificationEventElement, - Store.CONFIG, Operation.DELETED); - addValuesFromDataToElement(doc, change.getRemovedOperationalData(), dataChangedNotificationEventElement, - Store.OPERATION, Operation.DELETED); + addValuesFromDataToElement(doc, change.getRemovedPaths(), dataChangedNotificationEventElement, + Operation.DELETED); } /** @@ -320,13 +313,13 @@ public class ListenerAdapter implements DataChangeListener { * @param operation * {@link Operation} */ - private void addValuesFromDataToElement(final Document doc, final Set data, - final Element element, final Store store, final Operation operation) { + private void addValuesFromDataToElement(Document doc, Set data, Element element, + Operation operation) { if (data == null || data.isEmpty()) { return; } for (YangInstanceIdentifier path : data) { - Node node = createDataChangeEventElement(doc, path, null, store, operation); + Node node = createDataChangeEventElement(doc, path, null, operation); element.appendChild(node); } } @@ -345,13 +338,13 @@ public class ListenerAdapter implements DataChangeListener { * @param operation * {@link Operation} */ - private void addValuesFromDataToElement(final Document doc, final Map data, - final Element element, final Store store, final Operation operation) { + private void addValuesFromDataToElement(Document doc, Map data, Element element, + Operation operation) { if (data == null || data.isEmpty()) { return; } for (Entry entry : data.entrySet()) { - Node node = createDataChangeEventElement(doc, entry.getKey(), entry.getValue(), store, operation); + Node node = createDataChangeEventElement(doc, entry.getKey(), entry.getValue(), operation); element.appendChild(node); } } @@ -371,17 +364,17 @@ public class ListenerAdapter implements DataChangeListener { * {@link Operation} * @return {@link Node} node represented by changed event element. */ - private Node createDataChangeEventElement(final Document doc, final YangInstanceIdentifier path, - final CompositeNode data, final Store store, final Operation operation) { + private Node createDataChangeEventElement(Document doc, YangInstanceIdentifier path, CompositeNode data, + Operation operation) { Element dataChangeEventElement = doc.createElement("data-change-event"); Element pathElement = doc.createElement("path"); addPathAsValueToElement(path, pathElement); dataChangeEventElement.appendChild(pathElement); - Element storeElement = doc.createElement("store"); - storeElement.setTextContent(store.value); - dataChangeEventElement.appendChild(storeElement); + // Element storeElement = doc.createElement("store"); + // storeElement.setTextContent(store.value); + // dataChangeEventElement.appendChild(storeElement); Element operationElement = doc.createElement("operation"); operationElement.setTextContent(operation.value); @@ -530,7 +523,7 @@ public class ListenerAdapter implements DataChangeListener { * @param registration * ListenerRegistration */ - public void setRegistration(final ListenerRegistration registration) { + public void setRegistration(final ListenerRegistration registration) { this.registration = registration; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java index cf1bcd6a30..b911369cf0 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java @@ -15,12 +15,12 @@ import java.util.concurrent.locks.ReentrantLock; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; /** - * {@link Notificator} is responsible to create, remove and find {@link ListenerAdapter} listener. + * {@link Notificator} is responsible to create, remove and find + * {@link ListenerAdapter} listener. */ public class Notificator { private static Map listenersByStreamName = new ConcurrentHashMap<>(); - private static Map listenersByInstanceIdentifier = new ConcurrentHashMap<>(); private static final Lock lock = new ReentrantLock(); private Notificator() { @@ -44,26 +44,14 @@ public class Notificator { return listenersByStreamName.get(streamName); } - /** - * Gets {@link ListenerAdapter} listener specified by {@link YangInstanceIdentifier} path. - * - * @param path - * Path to data in data repository. - * @return ListenerAdapter - */ - public static ListenerAdapter getListenerFor(YangInstanceIdentifier path) { - return listenersByInstanceIdentifier.get(path); - } - /** * Checks if the listener specified by {@link YangInstanceIdentifier} path exist. * - * @param path - * Path to data in data repository. + * @param streamName * @return True if the listener exist, false otherwise. */ - public static boolean existListenerFor(YangInstanceIdentifier path) { - return listenersByInstanceIdentifier.containsKey(path); + public static boolean existListenerFor(String streamName) { + return listenersByStreamName.containsKey(streamName); } /** @@ -79,7 +67,6 @@ public class Notificator { ListenerAdapter listener = new ListenerAdapter(path, streamName); try { lock.lock(); - listenersByInstanceIdentifier.put(path, listener); listenersByStreamName.put(streamName, listener); } finally { lock.unlock(); @@ -89,16 +76,6 @@ public class Notificator { /** * Looks for listener determined by {@link YangInstanceIdentifier} path and removes it. - * - * @param path - * InstanceIdentifier - */ - public static void removeListener(YangInstanceIdentifier path) { - ListenerAdapter listener = listenersByInstanceIdentifier.get(path); - deleteListener(listener); - } - - /** * Creates String representation of stream name from URI. Removes slash from URI in start and end position. * * @param uri @@ -123,7 +100,7 @@ public class Notificator { * Removes all listeners. */ public static void removeAllListeners() { - for (ListenerAdapter listener : listenersByInstanceIdentifier.values()) { + for (ListenerAdapter listener : listenersByStreamName.values()) { try { listener.close(); } catch (Exception e) { @@ -132,7 +109,6 @@ public class Notificator { try { lock.lock(); listenersByStreamName = new ConcurrentHashMap<>(); - listenersByInstanceIdentifier = new ConcurrentHashMap<>(); } finally { lock.unlock(); } @@ -164,7 +140,6 @@ public class Notificator { } try { lock.lock(); - listenersByInstanceIdentifier.remove(listener.getPath()); listenersByStreamName.remove(listener.getStreamName()); } finally { lock.unlock(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang b/opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang new file mode 100644 index 0000000000..83934568cc --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang @@ -0,0 +1,31 @@ +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-7-8" { + } + + 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; + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonBasicYangTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonBasicYangTypesTest.java index 0f059f5024..d9dc26d888 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonBasicYangTypesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonBasicYangTypesTest.java @@ -35,6 +35,7 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.ModifyAction; import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; public class CnSnJsonBasicYangTypesTest extends YangAndXmlAndDataSchemaLoader { @@ -67,12 +68,12 @@ public class CnSnJsonBasicYangTypesTest extends YangAndXmlAndDataSchemaLoader { */ @Test public void xmlAndYangTypesWithJsonReaderTest() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/simple-yang-types/xml/data.xml", + Node node = TestUtils.readInputToCnSn("/cnsn-to-json/simple-yang-types/xml/data.xml", XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compositeNode, modules, searchedModuleName + ":" + searchedDataSchemaName); + TestUtils.normalizeCompositeNode(node, modules, searchedModuleName + ":" + searchedDataSchemaName); String jsonOutput = null; try { - jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, dataSchemaNode, + jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); } catch (WebApplicationException | IOException e) { } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java index 0d0ce5cdd3..632d2490ee 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java @@ -17,7 +17,8 @@ import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataValidationException; public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { @@ -31,7 +32,7 @@ public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { * return error because nodes has to be from one case below concrete choice. * */ - @Test + @Test(expected=DataValidationException.class) public void nodeSchemasOnVariousChoiceCasePathTest() { testWrapper("/cnsn-to-json/choice/xml/data_various_path_err.xml", "choice-case-test:cont"); } @@ -42,7 +43,7 @@ public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { * choice. * */ - @Test + @Test(expected=DataValidationException.class) public void nodeSchemasOnVariousChoiceCasePathAndMultipleChoicesTest() { testWrapper("/cnsn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml", "choice-case-test:cont"); @@ -116,10 +117,10 @@ public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { } private void testWrapper(String xmlPath, String pathToSchemaNode) { - CompositeNode compNode = TestUtils.readInputToCnSn(xmlPath, XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compNode, modules, pathToSchemaNode); + Node node = TestUtils.readInputToCnSn(xmlPath, XmlToCompositeNodeProvider.INSTANCE); + TestUtils.normalizeCompositeNode(node, modules, pathToSchemaNode); try { - TestUtils.writeCompNodeWithSchemaContextToOutput(compNode, modules, dataSchemaNode, + TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); } catch (WebApplicationException | IOException e) { // shouldn't end here diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java index 4b8b71440a..11051cc733 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java @@ -27,7 +27,7 @@ import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader { @@ -189,12 +189,12 @@ public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader @Test public void simpleYangDataTest() throws Exception { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/data.xml", + Node node = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/data.xml", XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compositeNode, modules, "simple-data-types:cont"); + TestUtils.normalizeCompositeNode(node, modules, "simple-data-types:cont"); - String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, dataSchemaNode, + String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); assertNotNull(jsonOutput); @@ -303,10 +303,10 @@ public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader public void testBadData() throws Exception { try { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/bad-data.xml", + Node node = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/bad-data.xml", XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compositeNode, modules, "simple-data-types:cont"); + TestUtils.normalizeCompositeNode(node, modules, "simple-data-types:cont"); fail("Expected RestconfDocumentedException"); } catch (RestconfDocumentedException e) { assertEquals("getErrorTag", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag()); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIncorrectTopLevelTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIncorrectTopLevelTest.java index 50c834b1ff..3bd600dbf1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIncorrectTopLevelTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIncorrectTopLevelTest.java @@ -21,7 +21,7 @@ import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; @@ -145,16 +145,15 @@ public class CnSnToJsonIncorrectTopLevelTest extends YangAndXmlAndDataSchemaLoad @Test public void incorrectTopLevelElementTest() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/data.xml", - XmlToCompositeNodeProvider.INSTANCE); + Node node = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/data.xml", XmlToCompositeNodeProvider.INSTANCE); DataSchemaNode incorrectDataSchema = null; incorrectDataSchema = new IncorrectDataSchema(); - TestUtils.normalizeCompositeNode(compositeNode, modules, "simple-data-types:cont"); + TestUtils.normalizeCompositeNode(node, modules, "simple-data-types:cont"); boolean exceptionRaised = false; try { - TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, incorrectDataSchema, + TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, incorrectDataSchema, StructuredDataToJsonProvider.INSTANCE); } catch (UnsupportedDataTypeException e) { exceptionRaised = true; diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java index 6e41dcb577..b5d3528e95 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java @@ -20,7 +20,7 @@ import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; /** * @@ -95,9 +95,9 @@ public class CnSnToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader { private String toJson(String xmlDataPath) { try { - CompositeNode compositeNode = TestUtils.readInputToCnSn(xmlDataPath, XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compositeNode, modules, searchedModuleName + ":" + searchedDataSchemaName); - return TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, dataSchemaNode, + Node node = TestUtils.readInputToCnSn(xmlDataPath, XmlToCompositeNodeProvider.INSTANCE); + TestUtils.normalizeCompositeNode(node, modules, searchedModuleName + ":" + searchedDataSchemaName); + return TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); } catch (WebApplicationException | IOException e) { } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java index eb6a5b9e00..72b9ed93d4 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java @@ -19,7 +19,7 @@ import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; public class CnSnToJsonWithAugmentTest extends YangAndXmlAndDataSchemaLoader { @@ -33,13 +33,13 @@ public class CnSnToJsonWithAugmentTest extends YangAndXmlAndDataSchemaLoader { */ @Test public void augmentedElementsToJson() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/augmentation/xml/data.xml", + Node node = TestUtils.readInputToCnSn("/cnsn-to-json/augmentation/xml/data.xml", XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compositeNode, modules, searchedModuleName + ":" + searchedDataSchemaName); + TestUtils.normalizeCompositeNode(node, modules, searchedModuleName + ":" + searchedDataSchemaName); String jsonOutput = null; try { - jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, dataSchemaNode, + jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); } catch (WebApplicationException | IOException e) { } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java index 4210944de7..3adfee7f5b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java @@ -13,12 +13,12 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.util.concurrent.CheckedFuture; import java.io.FileNotFoundException; import java.net.URI; import java.util.List; import org.junit.Before; import org.junit.Test; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; @@ -28,13 +28,10 @@ import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; -import org.opendaylight.controller.sal.restconf.impl.test.DummyFuture; -import org.opendaylight.controller.sal.restconf.impl.test.DummyFuture.Builder; -import org.opendaylight.controller.sal.restconf.impl.test.DummyRpcResult; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -62,11 +59,8 @@ public class RestPutListDataTest { restconfImpl = RestconfImpl.getInstance(); restconfImpl.setBroker(brokerFacade); restconfImpl.setControllerContext(controllerContext); - Builder futureBuilder = new DummyFuture.Builder(); - futureBuilder.rpcResult(new DummyRpcResult.Builder().result(TransactionStatus.COMMITED) - .build()); - when(brokerFacade.commitConfigurationDataPut(any(YangInstanceIdentifier.class), any(CompositeNode.class))) - .thenReturn(futureBuilder.build()); + when(brokerFacade.commitConfigurationDataPut(any(YangInstanceIdentifier.class), any(NormalizedNode.class))) + .thenReturn(mock(CheckedFuture.class)); } /** diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonIdentityrefToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonIdentityrefToCnSnTest.java index 23b040a9a3..cda635e847 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonIdentityrefToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonIdentityrefToCnSnTest.java @@ -31,15 +31,16 @@ public class JsonIdentityrefToCnSnTest extends YangAndXmlAndDataSchemaLoader { @Test public void jsonIdentityrefToCompositeNode() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/identityref/json/data.json", false, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/identityref/json/data.json", false, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertNotNull(node); - TestUtils.normalizeCompositeNode(compositeNode, modules, searchedModuleName + ":" + searchedDataSchemaName); + TestUtils.normalizeCompositeNode(node, modules, searchedModuleName + ":" + searchedDataSchemaName); - assertEquals("cont", compositeNode.getNodeType().getLocalName()); + assertEquals("cont", node.getNodeType().getLocalName()); - List> childs = compositeNode.getValue(); + assert(node instanceof CompositeNode); + List> childs = ((CompositeNode)node).getValue(); assertEquals(1, childs.size()); Node nd = childs.iterator().next(); assertTrue(nd instanceof CompositeNode); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonLeafrefToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonLeafrefToCnSnTest.java index 913e9f2d70..59696bc534 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonLeafrefToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonLeafrefToCnSnTest.java @@ -32,15 +32,16 @@ public class JsonLeafrefToCnSnTest extends YangAndXmlAndDataSchemaLoader { */ @Test public void jsonIdentityrefToCompositeNode() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/leafref/json/data.json", false, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/leafref/json/data.json", false, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); - TestUtils.normalizeCompositeNode(compositeNode, modules, searchedModuleName + ":" + searchedDataSchemaName); + assertNotNull(node); + TestUtils.normalizeCompositeNode(node, modules, searchedModuleName + ":" + searchedDataSchemaName); - assertEquals("cont", compositeNode.getNodeType().getLocalName()); + assertEquals("cont", node.getNodeType().getLocalName()); SimpleNode lf2 = null; - for (Node childNode : compositeNode.getValue()) { + assertTrue(node instanceof CompositeNode); + for (Node childNode : ((CompositeNode) node).getValue()) { if (childNode instanceof SimpleNode) { if (childNode.getNodeType().getLocalName().equals("lf2")) { lf2 = (SimpleNode) childNode; diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java index 7b71e42ab8..3699e4924f 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java @@ -11,6 +11,7 @@ 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.ByteArrayInputStream; import java.io.InputStream; @@ -52,19 +53,21 @@ public class JsonToCnSnTest { */ @Test public void multipleItemsInLeafList() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/multiple-leaflist-items.json", true, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/multiple-leaflist-items.json", true, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertNotNull(node); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; assertEquals(3, compositeNode.getValue().size()); boolean lflst1_1 = false; boolean lflst1_2 = false; boolean lflst1_3 = false; - for (Node node : compositeNode.getValue()) { - assertEquals("lflst1", node.getNodeType().getLocalName()); - assertTrue(node instanceof SimpleNode); - SimpleNode simpleNode = (SimpleNode) node; + for (Node nd : compositeNode.getValue()) { + assertEquals("lflst1", nd.getNodeType().getLocalName()); + assertTrue(nd instanceof SimpleNode); + SimpleNode simpleNode = (SimpleNode) nd; if (simpleNode.getValue().equals("45")) { lflst1_1 = true; } else if (simpleNode.getValue().equals("55")) { @@ -86,9 +89,12 @@ public class JsonToCnSnTest { */ @Test public void multipleItemsInListTest() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/multiple-items-in-list.json", true, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/multiple-items-in-list.json", true, JsonToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; + assertNotNull(compositeNode); assertEquals("lst", compositeNode.getNodeType().getLocalName()); @@ -97,9 +103,10 @@ public class JsonToCnSnTest { @Test public void nullArrayToSimpleNodeWithNullValueTest() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/array-with-null.json", true, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/array-with-null.json", true, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; assertEquals("cont", compositeNode.getNodeType().getLocalName()); assertNotNull(compositeNode.getValue()); @@ -163,10 +170,10 @@ public class JsonToCnSnTest { */ @Test public void emptyDataReadTest() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/empty-data.json", true, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/empty-data.json", true, JsonToCompositeNodeProvider.INSTANCE); - - assertNotNull(compositeNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; assertEquals("cont", compositeNode.getNodeType().getLocalName()); assertTrue(compositeNode instanceof CompositeNode); @@ -189,9 +196,9 @@ public class JsonToCnSnTest { @Test public void testJsonBlankInput() throws Exception { InputStream inputStream = new ByteArrayInputStream("".getBytes()); - CompositeNode compositeNode = JsonToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, - inputStream); - assertNull(compositeNode); + Node node = + JsonToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, inputStream); + assertNull( node ); } /** @@ -202,9 +209,10 @@ public class JsonToCnSnTest { @Test public void notSupplyNamespaceIfAlreadySupplied() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/simple-list.json", false, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/simple-list.json", false, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; // supplement namespaces according to first data schema - // "simple:data:types1" @@ -223,15 +231,21 @@ public class JsonToCnSnTest { assertEquals("lst", compNode.getNodeType().getLocalName()); verifyCompositeNode(compNode, "simple:list:yang1"); - TestUtils.normalizeCompositeNode(compositeNode, modules2, "simple-list-yang2:lst"); + try { + TestUtils.normalizeCompositeNode(compositeNode, modules2, "simple-list-yang2:lst"); + fail("Conversion to normalized node shouldn't be successfull because of different namespaces"); + } catch (IllegalStateException e) { + } +// veryfing has still meaning. despite exception, first phase where normalization of NodeWrappers is called passed successfuly. verifyCompositeNode(compNode, "simple:list:yang1"); } @Test public void jsonIdentityrefToCompositeNode() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/identityref/json/data.json", false, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/identityref/json/data.json", false, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; Set modules = TestUtils.loadModulesFrom("/json-to-cnsn/identityref"); assertEquals(2, modules.size()); @@ -298,8 +312,9 @@ public class JsonToCnSnTest { private CompositeNode loadAndNormalizeData(final String jsonPath, final String yangPath, final String topLevelElementName, final String moduleName) { - CompositeNode compositeNode = TestUtils.readInputToCnSn(jsonPath, false, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + Node node = TestUtils.readInputToCnSn(jsonPath, false, JsonToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; Set modules = null; modules = TestUtils.loadModulesFrom(yangPath); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java index 73f828c646..e50c07e05a 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java @@ -12,28 +12,34 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import com.google.common.collect.ImmutableMap; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; -import java.util.Map; +import com.google.common.util.concurrent.ListenableFuture; import java.util.concurrent.Future; +import org.apache.commons.lang.StringEscapeUtils; import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; -import org.opendaylight.controller.sal.core.api.data.DataBrokerService; -import org.opendaylight.controller.sal.core.api.data.DataChangeListener; -import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfError; @@ -44,7 +50,9 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +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; /** * Unit tests for BrokerFacade. @@ -54,73 +62,83 @@ import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; public class BrokerFacadeTest { @Mock - DataBrokerService dataBroker; - - @Mock - DataModificationTransaction mockTransaction; + DOMDataBroker domDataBroker; @Mock ConsumerSession mockConsumerSession; @Mock - MountInstance mockMountInstance; + DOMMountPoint mockMountInstance; BrokerFacade brokerFacade = BrokerFacade.getInstance(); - CompositeNode dataNode = TestUtils.readInputToCnSn("/parts/ietf-interfaces_interfaces.xml", - XmlToCompositeNodeProvider.INSTANCE); + CompositeNode dataNode; + + NormalizedNode dummyNode = createDummyNode("dummy:namespace", "2014-07-01", "dummy local name"); + ListenableFuture>> dummyNodeInFuture = wrapDummyNode(dummyNode); QName qname = QName.create("node"); YangInstanceIdentifier instanceID = YangInstanceIdentifier.builder().node(qname).toInstance(); + @Mock + DOMDataReadOnlyTransaction rTransaction; + + @Mock + DOMDataWriteTransaction wTransaction; + + @Mock + DOMDataReadWriteTransaction rwTransaction; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - - brokerFacade.setDataService(dataBroker); + // TODO it is started before every test method + brokerFacade.setDomDataBroker(domDataBroker); brokerFacade.setContext(mockConsumerSession); - } - - @Test - public void testReadConfigurationData() { - when(dataBroker.readConfigurationData(instanceID)).thenReturn(dataNode); + when(domDataBroker.newReadOnlyTransaction()).thenReturn(rTransaction); + when(domDataBroker.newWriteOnlyTransaction()).thenReturn(wTransaction); + when(domDataBroker.newReadWriteTransaction()).thenReturn(rwTransaction); - CompositeNode actualNode = brokerFacade.readConfigurationData(instanceID); + dataNode = TestUtils.prepareCompositeNodeWithIetfInterfacesInterfacesData(); - assertSame("readConfigurationData", dataNode, actualNode); } - @Test - public void testReadConfigurationDataBehindMountPoint() { - when(mockMountInstance.readConfigurationData(instanceID)).thenReturn(dataNode); - - CompositeNode actualNode = brokerFacade.readConfigurationDataBehindMountPoint(mockMountInstance, instanceID); + private ListenableFuture>> wrapDummyNode(NormalizedNode dummyNode) { + return Futures.>> immediateFuture(Optional.> of(dummyNode)); + } - assertSame("readConfigurationDataBehindMountPoint", dataNode, actualNode); + /** + * Value of this node shouldn't be important for testing purposes + */ + private NormalizedNode createDummyNode(String namespace, String date, String localName) { + return Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(QName.create(namespace, date, localName))).build(); } @Test - public void testReadOperationalData() { - when(dataBroker.readOperationalData(instanceID)).thenReturn(dataNode); + public void testReadConfigurationData() { + when(rTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn( + dummyNodeInFuture); - CompositeNode actualNode = brokerFacade.readOperationalData(instanceID); + NormalizedNode actualNode = brokerFacade.readConfigurationData(instanceID); - assertSame("readOperationalData", dataNode, actualNode); + assertSame("readConfigurationData", dummyNode, actualNode); } @Test - public void testReadOperationalDataBehindMountPoint() { - when(mockMountInstance.readOperationalData(instanceID)).thenReturn(dataNode); + public void testReadOperationalData() { + when(rTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn( + dummyNodeInFuture); - CompositeNode actualNode = brokerFacade.readOperationalDataBehindMountPoint(mockMountInstance, instanceID); + NormalizedNode actualNode = brokerFacade.readOperationalData(instanceID); - assertSame("readOperationalDataBehindMountPoint", dataNode, actualNode); + assertSame("readOperationalData", dummyNode, actualNode); } @Test(expected = RestconfDocumentedException.class) public void testReadOperationalDataWithNoDataBroker() { - brokerFacade.setDataService(null); + brokerFacade.setDomDataBroker(null); brokerFacade.readOperationalData(instanceID); } @@ -148,109 +166,46 @@ public class BrokerFacadeTest { @Test public void testCommitConfigurationDataPut() { - Future> expFuture = Futures.immediateFuture(null); - - when(dataBroker.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.commit()).thenReturn(expFuture); + CheckedFuture expFuture = mock(CheckedFuture.class); - Future> actualFuture = brokerFacade.commitConfigurationDataPut(instanceID, - dataNode); + when(wTransaction.submit()).thenReturn(expFuture); - assertSame("invokeRpc", expFuture, actualFuture); + Future actualFuture = brokerFacade.commitConfigurationDataPut(instanceID, dummyNode); - InOrder inOrder = inOrder(dataBroker, mockTransaction); - inOrder.verify(dataBroker).beginTransaction(); - inOrder.verify(mockTransaction).putConfigurationData(instanceID, dataNode); - inOrder.verify(mockTransaction).commit(); - } - - @Test - public void testCommitConfigurationDataPutBehindMountPoint() { - Future> expFuture = Futures.immediateFuture(null); - - when(mockMountInstance.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.commit()).thenReturn(expFuture); - - Future> actualFuture = brokerFacade.commitConfigurationDataPutBehindMountPoint( - mockMountInstance, instanceID, dataNode); - - assertSame("invokeRpc", expFuture, actualFuture); + assertSame("commitConfigurationDataPut", expFuture, actualFuture); - InOrder inOrder = inOrder(mockMountInstance, mockTransaction); - inOrder.verify(mockMountInstance).beginTransaction(); - inOrder.verify(mockTransaction).putConfigurationData(instanceID, dataNode); - inOrder.verify(mockTransaction).commit(); + InOrder inOrder = inOrder(domDataBroker, wTransaction); + inOrder.verify(domDataBroker).newWriteOnlyTransaction(); + inOrder.verify(wTransaction).put(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode); + inOrder.verify(wTransaction).submit(); } @Test public void testCommitConfigurationDataPost() { - Future> expFuture = Futures.immediateFuture(null); + CheckedFuture expFuture = mock(CheckedFuture.class); - Map nodeMap = new ImmutableMap.Builder() - .put(instanceID, dataNode).build(); + NormalizedNode dummyNode2 = createDummyNode("dummy:namespace2", "2014-07-01", "dummy local name2"); + when(rwTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( + wrapDummyNode(dummyNode2)); + when(rwTransaction.submit()).thenReturn(expFuture); - when(dataBroker.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.getCreatedConfigurationData()).thenReturn(nodeMap); - when(mockTransaction.commit()).thenReturn(expFuture); + CheckedFuture actualFuture = brokerFacade.commitConfigurationDataPost( + instanceID, dummyNode); - Future> actualFuture = brokerFacade.commitConfigurationDataPost(instanceID, - dataNode); + assertSame("commitConfigurationDataPost", expFuture, actualFuture); - assertSame("commitConfigurationDataPut", expFuture, actualFuture); - - InOrder inOrder = inOrder(dataBroker, mockTransaction); - inOrder.verify(dataBroker).beginTransaction(); - inOrder.verify(mockTransaction).putConfigurationData(instanceID, dataNode); - inOrder.verify(mockTransaction).commit(); + InOrder inOrder = inOrder(domDataBroker, rwTransaction); + inOrder.verify(domDataBroker).newReadWriteTransaction(); + inOrder.verify(rwTransaction).merge(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode); + inOrder.verify(rwTransaction).submit(); } @Test(expected = RestconfDocumentedException.class) public void testCommitConfigurationDataPostAlreadyExists() { - when(dataBroker.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.readConfigurationData(instanceID)).thenReturn(dataNode); - try { - brokerFacade.commitConfigurationDataPost(instanceID, dataNode); - } catch (RestconfDocumentedException e) { - assertEquals("getErrorTag", RestconfError.ErrorTag.DATA_EXISTS, e.getErrors().get(0).getErrorTag()); - throw e; - } - } - - @Test - public void testCommitConfigurationDataPostBehindMountPoint() { - Future> expFuture = Futures.immediateFuture(null); - - Map nodeMap = new ImmutableMap.Builder() - .put(instanceID, dataNode).build(); - - when(mockMountInstance.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.getCreatedConfigurationData()).thenReturn(nodeMap); - when(mockTransaction.commit()).thenReturn(expFuture); - - Future> actualFuture = brokerFacade.commitConfigurationDataPostBehindMountPoint( - mockMountInstance, instanceID, dataNode); - - assertSame("commitConfigurationDataPostBehindMountPoint", expFuture, actualFuture); - - InOrder inOrder = inOrder(mockMountInstance, mockTransaction); - inOrder.verify(mockMountInstance).beginTransaction(); - inOrder.verify(mockTransaction).putConfigurationData(instanceID, dataNode); - inOrder.verify(mockTransaction).commit(); - } - - @Test(expected = RestconfDocumentedException.class) - public void testCommitConfigurationDataPostBehindMountPointAlreadyExists() { - - when(mockMountInstance.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.readConfigurationData(instanceID)).thenReturn(dataNode); + when(rwTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( + dummyNodeInFuture); try { - brokerFacade.commitConfigurationDataPostBehindMountPoint(mockMountInstance, instanceID, dataNode); + brokerFacade.commitConfigurationDataPost(instanceID, dummyNode); } catch (RestconfDocumentedException e) { assertEquals("getErrorTag", RestconfError.ErrorTag.DATA_EXISTS, e.getErrors().get(0).getErrorTag()); throw e; @@ -259,43 +214,19 @@ public class BrokerFacadeTest { @Test public void testCommitConfigurationDataDelete() { - Future> expFuture = Futures.immediateFuture(null); + CheckedFuture expFuture = mock(CheckedFuture.class); - when(dataBroker.beginTransaction()).thenReturn(mockTransaction); - when(mockTransaction.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn( - ImmutableCompositeNode.builder().toInstance()); - mockTransaction.removeConfigurationData(instanceID); - when(mockTransaction.commit()).thenReturn(expFuture); + when(wTransaction.submit()).thenReturn(expFuture); - Future> actualFuture = brokerFacade.commitConfigurationDataDelete(instanceID); + CheckedFuture actualFuture = brokerFacade + .commitConfigurationDataDelete(instanceID); assertSame("commitConfigurationDataDelete", expFuture, actualFuture); - InOrder inOrder = inOrder(dataBroker, mockTransaction); - inOrder.verify(dataBroker).beginTransaction(); - inOrder.verify(mockTransaction).removeConfigurationData(instanceID); - inOrder.verify(mockTransaction).commit(); - } - - @Test - public void testCommitConfigurationDataDeleteBehindMountPoint() { - Future> expFuture = Futures.immediateFuture(null); - - when(mockMountInstance.beginTransaction()).thenReturn(mockTransaction); - when(mockTransaction.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn( - ImmutableCompositeNode.builder().toInstance()); - mockTransaction.removeConfigurationData(instanceID); - when(mockTransaction.commit()).thenReturn(expFuture); - - Future> actualFuture = brokerFacade.commitConfigurationDataDeleteBehindMountPoint( - mockMountInstance, instanceID); - - assertSame("commitConfigurationDataDeleteBehindMountPoint", expFuture, actualFuture); - - InOrder inOrder = inOrder(mockMountInstance, mockTransaction); - inOrder.verify(mockMountInstance).beginTransaction(); - inOrder.verify(mockTransaction).removeConfigurationData(instanceID); - inOrder.verify(mockTransaction).commit(); + InOrder inOrder = inOrder(domDataBroker, wTransaction); + inOrder.verify(domDataBroker).newWriteOnlyTransaction(); + inOrder.verify(wTransaction).delete(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class)); + inOrder.verify(wTransaction).submit(); } @SuppressWarnings("unchecked") @@ -303,16 +234,23 @@ public class BrokerFacadeTest { public void testRegisterToListenDataChanges() { ListenerAdapter listener = Notificator.createListener(instanceID, "stream"); - ListenerRegistration mockRegistration = mock(ListenerRegistration.class); - when(dataBroker.registerDataChangeListener(instanceID, listener)).thenReturn(mockRegistration); + ListenerRegistration mockRegistration = mock(ListenerRegistration.class); + + when( + domDataBroker.registerDataChangeListener(any(LogicalDatastoreType.class), eq(instanceID), eq(listener), + eq(DataChangeScope.BASE))).thenReturn(mockRegistration); - brokerFacade.registerToListenDataChanges(listener); + brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE, listener); - verify(dataBroker).registerDataChangeListener(instanceID, listener); + verify(domDataBroker).registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, instanceID, listener, + DataChangeScope.BASE); assertEquals("isListening", true, listener.isListening()); - brokerFacade.registerToListenDataChanges(listener); - verifyNoMoreInteractions(dataBroker); + brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE, listener); + verifyNoMoreInteractions(domDataBroker); + + String escapeXml = StringEscapeUtils.escapeXml("data might contain & or ! or % or ' "); + System.out.println(escapeXml); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java index 9aab841546..500baafab3 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java @@ -36,7 +36,8 @@ import javax.ws.rs.core.UriInfo; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode; @@ -317,9 +318,10 @@ public class InvokeRpcMethodTest { RpcDefinition mockRpc = mock(RpcDefinition.class); when(mockRpc.getQName()).thenReturn(cancelToastQName); - MountInstance mockMountPoint = mock(MountInstance.class); - when(mockMountPoint.rpc(eq(cancelToastQName), any(CompositeNode.class))).thenReturn(mockListener); - + DOMMountPoint mockMountPoint = mock(DOMMountPoint.class); + RpcProvisionRegistry mockedRpcProvisionRegistry = mock(RpcProvisionRegistry.class); + when(mockedRpcProvisionRegistry.invokeRpc(eq(cancelToastQName), any(CompositeNode.class))).thenReturn(mockListener); + when(mockMountPoint.getService(eq(RpcProvisionRegistry.class))).thenReturn(Optional.of(mockedRpcProvisionRegistry)); when(mockMountPoint.getSchemaContext()).thenReturn(TestUtils.loadSchemaContext("/invoke-rpc")); InstanceIdWithSchemaNode mockedInstanceId = mock(InstanceIdWithSchemaNode.class); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MultipleEqualNamesForDataNodesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MultipleEqualNamesForDataNodesTest.java index 5fbfc45352..478565f033 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MultipleEqualNamesForDataNodesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MultipleEqualNamesForDataNodesTest.java @@ -21,7 +21,7 @@ import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException import org.opendaylight.controller.sal.restconf.impl.RestconfError; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.model.api.Module; /** @@ -57,16 +57,16 @@ public class MultipleEqualNamesForDataNodesTest { } private void multipleEqualNameDataNodeTest(String path, ErrorType errorType, ErrorTag errorTag, - MessageBodyReader messageBodyReader) { + MessageBodyReader> messageBodyReader) { try { - CompositeNode compositeNode = TestUtils.readInputToCnSn(path, false, messageBodyReader); - assertNotNull(compositeNode); + Node node = TestUtils.readInputToCnSn(path, false, messageBodyReader); + assertNotNull(node); Set modules = null; modules = TestUtils.loadModulesFrom("/equal-data-node-names/yang"); assertNotNull(modules); - TestUtils.normalizeCompositeNode(compositeNode, modules, "equal-data-node-names" + ":" + "cont"); + TestUtils.normalizeCompositeNode(node, modules, "equal-data-node-names" + ":" + "cont"); fail("Exception RestconfDocumentedException should be raised"); } catch (RestconfDocumentedException e) { List errors = e.getErrors(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java index 66ced81817..8d5cac0204 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java @@ -10,13 +10,14 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.util.concurrent.CheckedFuture; import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException; import java.util.Set; -import java.util.concurrent.Future; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -24,13 +25,12 @@ 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.common.api.TransactionStatus; import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -70,21 +70,14 @@ public class RestDeleteOperationTest extends JerseyTest { @Test public void deleteConfigStatusCodes() throws UnsupportedEncodingException { String uri = "/config/test-interface:interfaces"; - Future> dummyFuture = createFuture(TransactionStatus.COMMITED); - when(brokerFacade.commitConfigurationDataDelete(any(YangInstanceIdentifier.class))).thenReturn(dummyFuture); + when(brokerFacade.commitConfigurationDataDelete(any(YangInstanceIdentifier.class))).thenReturn( + mock(CheckedFuture.class)); Response response = target(uri).request(MediaType.APPLICATION_XML).delete(); assertEquals(200, response.getStatus()); - dummyFuture = createFuture(TransactionStatus.FAILED); - when(brokerFacade.commitConfigurationDataDelete(any(YangInstanceIdentifier.class))).thenReturn(dummyFuture); + doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataDelete( + any(YangInstanceIdentifier.class)); response = target(uri).request(MediaType.APPLICATION_XML).delete(); assertEquals(500, response.getStatus()); } - - private Future> createFuture(TransactionStatus statusName) { - RpcResult rpcResult = new DummyRpcResult.Builder().result(statusName) - .build(); - return new DummyFuture.Builder().rpcResult(rpcResult).build(); - } - } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java index ac660e32bc..d4f6909081 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java @@ -18,8 +18,10 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import java.io.FileNotFoundException; -import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; @@ -33,40 +35,46 @@ import java.util.Map; 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.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.core.api.mount.MountService; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider; import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; -import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; -import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +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.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; +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.data.impl.util.CompositeNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -74,9 +82,6 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - public class RestGetOperationTest extends JerseyTest { static class NodeData { @@ -93,7 +98,7 @@ public class RestGetOperationTest extends JerseyTest { private static RestconfImpl restconfImpl; private static SchemaContext schemaContextYangsIetf; private static SchemaContext schemaContextTestModule; - private static CompositeNode answerFromGet; + private static NormalizedNode answerFromGet; private static SchemaContext schemaContextModules; private static SchemaContext schemaContextBehindMountPoint; @@ -101,7 +106,7 @@ public class RestGetOperationTest extends JerseyTest { private static final String RESTCONF_NS = "urn:ietf:params:xml:ns:yang:ietf-restconf"; @BeforeClass - public static void init() throws FileNotFoundException { + public static void init() throws FileNotFoundException, ParseException { schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs"); schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module"); ControllerContext controllerContext = ControllerContext.getInstance(); @@ -110,7 +115,7 @@ public class RestGetOperationTest extends JerseyTest { restconfImpl = RestconfImpl.getInstance(); restconfImpl.setBroker(brokerFacade); restconfImpl.setControllerContext(controllerContext); - answerFromGet = prepareCompositeNodeWithIetfInterfacesInterfacesData(); + answerFromGet = TestUtils.prepareNormalizedNodeWithIetfInterfacesInterfacesData(); schemaContextModules = TestUtils.loadSchemaContext("/modules"); schemaContextBehindMountPoint = TestUtils.loadSchemaContext("/modules/modules-behind-mount-point"); @@ -161,14 +166,13 @@ public class RestGetOperationTest extends JerseyTest { * MountPoint test. URI represents mount point. */ @Test - public void getDataWithUrlMountPoint() throws UnsupportedEncodingException, URISyntaxException { - when( - brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class), - any(YangInstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest()); - MountInstance mountInstance = mock(MountInstance.class); + public void getDataWithUrlMountPoint() throws UnsupportedEncodingException, URISyntaxException, ParseException { + when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class))).thenReturn( + prepareCnDataForMountPointTest(false)); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); @@ -188,20 +192,18 @@ public class RestGetOperationTest extends JerseyTest { * {@link BrokerFacade#readConfigurationDataBehindMountPoint(MountInstance, YangInstanceIdentifier)} which is called in * method {@link RestconfImpl#readConfigurationData} * - * * @throws ParseException */ @Test public void getDataWithSlashesBehindMountPoint() throws UnsupportedEncodingException, URISyntaxException, ParseException { YangInstanceIdentifier awaitedInstanceIdentifier = prepareInstanceIdentifierForList(); - when( - brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class), - eq(awaitedInstanceIdentifier))).thenReturn(prepareCnDataForMountPointTest()); - MountInstance mountInstance = mock(MountInstance.class); + when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), eq(awaitedInstanceIdentifier))).thenReturn( + prepareCnDataForSlashesBehindMountPointTest()); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); @@ -219,24 +221,25 @@ public class RestGetOperationTest extends JerseyTest { QName qNameKeyList = QName.create(uri, revision, "lf11"); parameters.add(new YangInstanceIdentifier.NodeIdentifier(qNameCont)); + parameters.add(new YangInstanceIdentifier.NodeIdentifier(qNameList)); parameters.add(new YangInstanceIdentifier.NodeIdentifierWithPredicates(qNameList, qNameKeyList, "GigabitEthernet0/0/0/0")); return YangInstanceIdentifier.create(parameters); } @Test - public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException { - when( - brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class), - any(YangInstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest()); - MountInstance mountInstance = mock(MountInstance.class); + public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException, + ParseException { + when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class))).thenReturn( + prepareCnDataForMountPointTest(true)); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); - String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/"; + String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont"; assertEquals(200, get(uri, MediaType.APPLICATION_XML)); } @@ -361,10 +364,10 @@ public class RestGetOperationTest extends JerseyTest { ControllerContext controllerContext = ControllerContext.getInstance(); controllerContext.setGlobalSchema(schemaContextModules); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); controllerContext.setMountService(mockMountService); @@ -450,10 +453,10 @@ public class RestGetOperationTest extends JerseyTest { ControllerContext controllerContext = ControllerContext.getInstance(); controllerContext.setGlobalSchema(schemaContextModules); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); controllerContext.setMountService(mockMountService); @@ -484,10 +487,10 @@ public class RestGetOperationTest extends JerseyTest { ControllerContext controllerContext = ControllerContext.getInstance(); controllerContext.setGlobalSchema(schemaContextModules); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); controllerContext.setMountService(mockMountService); @@ -636,11 +639,30 @@ public class RestGetOperationTest extends JerseyTest { return target(uri).request(mediaType).get().getStatus(); } - private CompositeNode prepareCnDataForMountPointTest() throws URISyntaxException { - CompositeNodeWrapper cont1 = new CompositeNodeWrapper(new URI("test:module"), "cont1"); - SimpleNodeWrapper lf11 = new SimpleNodeWrapper(new URI("test:module"), "lf11", "lf11 value"); - cont1.addValue(lf11); - return cont1.unwrap(); + /** + container cont { + container cont1 { + leaf lf11 { + type string; + } + */ + private NormalizedNode prepareCnDataForMountPointTest(boolean wrapToCont) throws URISyntaxException, ParseException { + String testModuleDate = "2014-01-09"; + 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() { @@ -651,22 +673,20 @@ public class RestGetOperationTest extends JerseyTest { when(brokerFacade.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn(answerFromGet); } - private static CompositeNode prepareCompositeNodeWithIetfInterfacesInterfacesData() { - CompositeNode intface; - try { - intface = new CompositeNodeWrapper(new URI("interface"), "interface"); - List> childs = new ArrayList<>(); - - childs.add(new SimpleNodeWrapper(new URI("name"), "name", "eth0")); - childs.add(new SimpleNodeWrapper(new URI("type"), "type", "ethernetCsmacd")); - childs.add(new SimpleNodeWrapper(new URI("enabled"), "enabled", Boolean.FALSE)); - childs.add(new SimpleNodeWrapper(new URI("description"), "description", "some interface")); - intface.setValue(childs); - return intface; - } catch (URISyntaxException e) { - } - - return null; + private NormalizedNode prepareCnDataForSlashesBehindMountPointTest() throws ParseException { + CollectionNodeBuilder lst1 = ImmutableMapNodeBuilder.create(); + lst1.withNodeIdentifier(TestUtils.getNodeIdentifier("lst1", "test:module", "2014-01-09")); + lst1.withChild(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()); + + return lst1.build(); } /** @@ -682,6 +702,7 @@ public class RestGetOperationTest extends JerseyTest { private void getDataWithUriIncludeWhiteCharsParameter(final String target) throws UnsupportedEncodingException { mockReadConfigurationDataMethod(); + mockReadOperationalDataMethod(); String uri = "/" + target + "/ietf-interfaces:interfaces/interface/eth0"; Response response = target(uri).queryParam("prettyPrint", "false").request("application/xml").get(); String xmlData = response.readEntity(String.class); @@ -726,7 +747,14 @@ public class RestGetOperationTest extends JerseyTest { toSimpleNodeData(toNestedQName("depth3-leaf2"), "depth3-leaf2-value")), toSimpleNodeData(toNestedQName("depth2-leaf1"), "depth2-leaf1-value"))); - when(brokerFacade.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn(depth1Cont); + Module module = TestUtils.findModule(schemaContextModules.getModules(), "nested-module"); + assertNotNull(module); + + DataSchemaNode dataSchemaNode = TestUtils.resolveDataSchemaNode("depth1-cont", module); + assertNotNull(dataSchemaNode); + + when(brokerFacade.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn( + TestUtils.compositeNodeToDatastoreNormalizedNode(depth1Cont, dataSchemaNode)); // Test config with depth 1 @@ -852,7 +880,18 @@ public class RestGetOperationTest extends JerseyTest { toSimpleNodeData(toNestedQName("depth4-leaf1"), "depth4-leaf1-value")), toSimpleNodeData(toNestedQName("depth3-leaf1"), "depth3-leaf1-value"))); - when(brokerFacade.readOperationalData(any(YangInstanceIdentifier.class))).thenReturn(depth2Cont1); + assertTrue(dataSchemaNode instanceof DataNodeContainer); + DataSchemaNode depth2cont1Schema = null; + for (DataSchemaNode childNode : ((DataNodeContainer) dataSchemaNode).getChildNodes()) { + if (childNode.getQName().getLocalName().equals("depth2-cont1")) { + depth2cont1Schema = childNode; + break; + } + } + assertNotNull(depth2Cont1); + + when(brokerFacade.readOperationalData(any(YangInstanceIdentifier.class))).thenReturn( + TestUtils.compositeNodeToDatastoreNormalizedNode(depth2Cont1, depth2cont1Schema)); response = target("/operational/nested-module:depth1-cont/depth2-cont1").queryParam("depth", "3") .request("application/xml").get(); @@ -876,7 +915,7 @@ public class RestGetOperationTest extends JerseyTest { UriInfo mockInfo = mock(UriInfo.class); when(mockInfo.getQueryParameters(false)).thenAnswer(new Answer>() { @Override - public MultivaluedMap answer(final InvocationOnMock invocation) { + public MultivaluedMap answer(InvocationOnMock invocation) { return paramMap; } }); @@ -901,8 +940,9 @@ public class RestGetOperationTest extends JerseyTest { } private void verifyXMLResponse(final Response response, final NodeData nodeData) { - - Document doc = TestUtils.loadDocumentFrom((InputStream) response.getEntity()); + Document doc = response.readEntity(Document.class); +// Document doc = TestUtils.loadDocumentFrom((InputStream) response.getEntity()); +// System.out.println(); assertNotNull("Could not parse XML document", doc); // System.out.println(TestUtils.getDocumentInPrintableForm( doc )); @@ -913,11 +953,11 @@ public class RestGetOperationTest extends JerseyTest { @SuppressWarnings("unchecked") private void verifyContainerElement(final Element element, final NodeData nodeData) { - assertEquals("Element local name", nodeData.key, element.getNodeName()); + assertEquals("Element local name", nodeData.key, element.getLocalName()); NodeList childNodes = element.getChildNodes(); if (nodeData.data == null) { // empty container - assertTrue("Expected no child elements for \"" + element.getNodeName() + "\"", childNodes.getLength() == 0); + assertTrue("Expected no child elements for \"" + element.getLocalName() + "\"", childNodes.getLength() == 0); return; } @@ -933,21 +973,21 @@ public class RestGetOperationTest extends JerseyTest { } Element actualElement = (Element) actualChild; - NodeData expChild = expChildMap.remove(actualElement.getNodeName()); + NodeData expChild = expChildMap.remove(actualElement.getLocalName()); assertNotNull( - "Unexpected child element for parent \"" + element.getNodeName() + "\": " - + actualElement.getNodeName(), expChild); + "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.getNodeName(), expChild.data, + assertEquals("Text content for element: " + actualElement.getLocalName(), expChild.data, actualElement.getTextContent()); } } if (!expChildMap.isEmpty()) { - fail("Missing elements for parent \"" + element.getNodeName() + "\": " + expChildMap.keySet()); + fail("Missing elements for parent \"" + element.getLocalName() + "\": " + expChildMap.keySet()); } } @@ -990,4 +1030,5 @@ public class RestGetOperationTest extends JerseyTest { private NodeData toSimpleNodeData(final QName key, final Object value) { return new NodeData(key, value); } + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java index 979b58b78a..97cd67d34b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java @@ -9,12 +9,16 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; 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.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; import java.io.IOException; import java.io.InputStream; @@ -27,7 +31,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.concurrent.Future; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; @@ -37,8 +40,8 @@ import org.junit.BeforeClass; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.core.api.mount.MountService; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider; import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper; @@ -48,14 +51,16 @@ import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; 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.RpcError.ErrorType; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -77,7 +82,7 @@ public class RestPostOperationTest extends JerseyTest { private static SchemaContext schemaContextTestModule; private static SchemaContext schemaContext; - private static MountService mountService; + private static DOMMountPointService mountService; @BeforeClass public static void init() throws URISyntaxException, IOException { @@ -124,10 +129,9 @@ public class RestPostOperationTest extends JerseyTest { assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataRpcInput)); List rpcErrors = new ArrayList<>(); - rpcErrors.add( RpcResultBuilder.newError( ErrorType.RPC, "tag1", "message1", - "applicationTag1", "info1", null ) ); - rpcErrors.add( RpcResultBuilder.newWarning( ErrorType.PROTOCOL, "tag2", "message2", - "applicationTag2", "info2", null ) ); + rpcErrors.add(RpcResultBuilder.newError(ErrorType.RPC, "tag1", "message1", "applicationTag1", "info1", null)); + rpcErrors.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "tag2", "message2", "applicationTag2", "info2", + null)); mockInvokeRpc(null, false, rpcErrors); assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataRpcInput)); @@ -138,28 +142,25 @@ public class RestPostOperationTest extends JerseyTest { @Test public void postConfigOnlyStatusCodes() throws UnsupportedEncodingException { controllerContext.setSchemas(schemaContextYangsIetf); - mockCommitConfigurationDataPostMethod(TransactionStatus.COMMITED); String uri = "/config"; + mockCommitConfigurationDataPostMethod(true); assertEquals(204, post(uri, MediaType.APPLICATION_XML, xmlDataAbsolutePath)); - mockCommitConfigurationDataPostMethod(null); - assertEquals(202, post(uri, MediaType.APPLICATION_XML, xmlDataAbsolutePath)); - - mockCommitConfigurationDataPostMethod(TransactionStatus.FAILED); + mockCommitConfigurationDataPostMethod(false); assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataAbsolutePath)); + + assertEquals(400, post(uri, MediaType.APPLICATION_XML, "")); } @Test public void postConfigStatusCodes() throws UnsupportedEncodingException { controllerContext.setSchemas(schemaContextYangsIetf); - mockCommitConfigurationDataPostMethod(TransactionStatus.COMMITED); String uri = "/config/ietf-interfaces:interfaces"; - assertEquals(204, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath)); - mockCommitConfigurationDataPostMethod(null); - assertEquals(202, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath)); + mockCommitConfigurationDataPostMethod(true); + assertEquals(204, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath)); - mockCommitConfigurationDataPostMethod(TransactionStatus.FAILED); + mockCommitConfigurationDataPostMethod(false); assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath)); assertEquals(400, post(uri, MediaType.APPLICATION_JSON, "")); @@ -168,18 +169,14 @@ public class RestPostOperationTest extends JerseyTest { @Test public void postDataViaUrlMountPoint() throws UnsupportedEncodingException { controllerContext.setSchemas(schemaContextYangsIetf); - RpcResult rpcResult = new DummyRpcResult.Builder().result( - TransactionStatus.COMMITED).build(); - Future> dummyFuture = new DummyFuture.Builder().rpcResult( - rpcResult).build(); when( - brokerFacade.commitConfigurationDataPostBehindMountPoint(any(MountInstance.class), - any(YangInstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); + brokerFacade.commitConfigurationDataPost(any(DOMMountPoint.class), any(YangInstanceIdentifier.class), + any(NormalizedNode.class))).thenReturn(mock(CheckedFuture.class)); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); @@ -207,18 +204,13 @@ public class RestPostOperationTest extends JerseyTest { mockInvokeRpc(result, sucessful, Collections. emptyList()); } - private void mockCommitConfigurationDataPostMethod(TransactionStatus statusName) { - RpcResult rpcResult = new DummyRpcResult.Builder().result(statusName) - .build(); - Future> dummyFuture = null; - if (statusName != null) { - dummyFuture = new DummyFuture.Builder().rpcResult(rpcResult).build(); + private void mockCommitConfigurationDataPostMethod(final boolean succesfulComit) { + if (succesfulComit) { + doReturn(mock(CheckedFuture.class)).when(brokerFacade).commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(NormalizedNode.class)); } else { - dummyFuture = new DummyFuture.Builder().build(); + doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataPost( + any(YangInstanceIdentifier.class), any(NormalizedNode.class)); } - - when(brokerFacade.commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(CompositeNode.class))) - .thenReturn(dummyFuture); } @Test @@ -226,14 +218,12 @@ public class RestPostOperationTest extends JerseyTest { initMocking(); RpcResult rpcResult = new DummyRpcResult.Builder().result( TransactionStatus.COMMITED).build(); - Future> dummyFuture = new DummyFuture.Builder().rpcResult( - rpcResult).build(); - when(brokerFacade.commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(CompositeNode.class))) - .thenReturn(dummyFuture); + when(brokerFacade.commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(NormalizedNode.class))) + .thenReturn(mock(CheckedFuture.class)); ArgumentCaptor instanceIdCaptor = ArgumentCaptor.forClass(YangInstanceIdentifier.class); - ArgumentCaptor compNodeCaptor = ArgumentCaptor.forClass(CompositeNode.class); + ArgumentCaptor compNodeCaptor = ArgumentCaptor.forClass(NormalizedNode.class); String URI_1 = "/config"; assertEquals(204, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface)); @@ -253,20 +243,20 @@ public class RestPostOperationTest extends JerseyTest { public void createConfigurationDataNullTest() throws UnsupportedEncodingException { initMocking(); - when(brokerFacade.commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(CompositeNode.class))) + when(brokerFacade.commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(NormalizedNode.class))) .thenReturn(null); String URI_1 = "/config"; - assertEquals(202, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface)); + assertEquals(204, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface)); String URI_2 = "/config/test-interface:interfaces"; - assertEquals(202, post(URI_2, Draft02.MediaTypes.DATA + XML, xmlBlockData)); + assertEquals(204, post(URI_2, Draft02.MediaTypes.DATA + XML, xmlBlockData)); } private static void initMocking() { controllerContext = ControllerContext.getInstance(); controllerContext.setSchemas(schemaContext); - mountService = mock(MountService.class); + mountService = mock(DOMMountPointService.class); controllerContext.setMountService(mountService); brokerFacade = mock(BrokerFacade.class); restconfImpl = RestconfImpl.getInstance(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java index 5d837f42bd..3284546dcb 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java @@ -9,15 +9,18 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.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 com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; -import java.util.concurrent.Future; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; @@ -26,9 +29,9 @@ 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.common.api.TransactionStatus; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.core.api.mount.MountService; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider; import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; @@ -36,10 +39,10 @@ import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; public class RestPutOperationTest extends JerseyTest { @@ -96,10 +99,10 @@ public class RestPutOperationTest extends JerseyTest { @Test public void putConfigStatusCodes() throws UnsupportedEncodingException { String uri = "/config/ietf-interfaces:interfaces/interface/eth0"; - mockCommitConfigurationDataPutMethod(TransactionStatus.COMMITED); + mockCommitConfigurationDataPutMethod(true); assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData)); - mockCommitConfigurationDataPutMethod(TransactionStatus.FAILED); + mockCommitConfigurationDataPutMethod(false); assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData)); assertEquals(400, put(uri, MediaType.APPLICATION_JSON, "")); @@ -117,18 +120,16 @@ public class RestPutOperationTest extends JerseyTest { public void testRpcResultCommitedToStatusCodesWithMountPoint() throws UnsupportedEncodingException, FileNotFoundException, URISyntaxException { - RpcResult rpcResult = new DummyRpcResult.Builder().result( - TransactionStatus.COMMITED).build(); - Future> dummyFuture = new DummyFuture.Builder().rpcResult( - rpcResult).build(); + CheckedFuture dummyFuture = mock(CheckedFuture.class); + when( - brokerFacade.commitConfigurationDataPutBehindMountPoint(any(MountInstance.class), - any(YangInstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); + brokerFacade.commitConfigurationDataPut(any(DOMMountPoint.class), any(YangInstanceIdentifier.class), + any(NormalizedNode.class))).thenReturn(dummyFuture); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); @@ -141,18 +142,15 @@ public class RestPutOperationTest extends JerseyTest { @Test public void putDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException { - RpcResult rpcResult = new DummyRpcResult.Builder().result( - TransactionStatus.COMMITED).build(); - Future> dummyFuture = new DummyFuture.Builder().rpcResult( - rpcResult).build(); + CheckedFuture dummyFuture = mock(CheckedFuture.class); when( - brokerFacade.commitConfigurationDataPutBehindMountPoint(any(MountInstance.class), - any(YangInstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); + brokerFacade.commitConfigurationDataPut(any(DOMMountPoint.class), any(YangInstanceIdentifier.class), + any(NormalizedNode.class))).thenReturn(dummyFuture); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); @@ -164,13 +162,14 @@ public class RestPutOperationTest extends JerseyTest { return target(uri).request(mediaType).put(Entity.entity(data, mediaType)).getStatus(); } - private void mockCommitConfigurationDataPutMethod(TransactionStatus statusName) { - RpcResult rpcResult = new DummyRpcResult.Builder().result(statusName) - .build(); - Future> dummyFuture = new DummyFuture.Builder().rpcResult( - rpcResult).build(); - when(brokerFacade.commitConfigurationDataPut(any(YangInstanceIdentifier.class), any(CompositeNode.class))) - .thenReturn(dummyFuture); + private void mockCommitConfigurationDataPutMethod(final boolean noErrors) { + if (noErrors) { + doReturn(mock(CheckedFuture.class)).when(brokerFacade).commitConfigurationDataPut( + any(YangInstanceIdentifier.class), any(NormalizedNode.class)); + } else { + doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataPut( + any(YangInstanceIdentifier.class), any(NormalizedNode.class)); + } } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java index 236712b454..906695b3aa 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java @@ -15,16 +15,16 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import java.io.FileNotFoundException; +import java.text.ParseException; import java.util.Set; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -54,12 +54,12 @@ public class RestconfImplTest { } @Test - public void testExample() throws FileNotFoundException { - CompositeNode loadedCompositeNode = TestUtils.readInputToCnSn("/parts/ietf-interfaces_interfaces.xml", - XmlToCompositeNodeProvider.INSTANCE); + public void testExample() throws FileNotFoundException, ParseException { + NormalizedNode normalizedNodeData = TestUtils.prepareNormalizedNodeWithIetfInterfacesInterfacesData(); BrokerFacade brokerFacade = mock(BrokerFacade.class); - when(brokerFacade.readOperationalData(any(YangInstanceIdentifier.class))).thenReturn(loadedCompositeNode); - assertEquals(loadedCompositeNode, brokerFacade.readOperationalData(null)); + when(brokerFacade.readOperationalData(any(YangInstanceIdentifier.class))).thenReturn(normalizedNodeData); + assertEquals(normalizedNodeData, + brokerFacade.readOperationalData(null)); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java index 67d98f6b55..562cac0bcf 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java @@ -14,6 +14,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; @@ -25,8 +26,12 @@ import java.io.OutputStreamWriter; import java.net.URI; import java.net.URISyntaxException; import java.sql.Date; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -42,20 +47,37 @@ 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.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.NodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.controller.sal.restconf.impl.RestconfError; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; import org.opendaylight.controller.sal.restconf.impl.StructuredData; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +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.composite.node.schema.cnsn.parser.CnSnToNormalizedNodeParserFactory; +import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; +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.data.impl.util.CompositeNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; 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.SchemaContext; -import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser; +import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,7 +88,7 @@ public final class TestUtils { private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class); - private final static YangModelParser parser = new YangParserImpl(); + private final static YangContextParser parser = new YangParserImpl(); private static Set loadModules(String resourceDirectory) throws FileNotFoundException { final File testDir = new File(resourceDirectory); @@ -151,12 +173,12 @@ public final class TestUtils { * {@code dataSchemaNode}. The method {@link RestconfImpl#createConfigurationData createConfigurationData} is used * because it contains calling of method {code normalizeNode} */ - public static void normalizeCompositeNode(CompositeNode compositeNode, Set modules, String schemaNodePath) { + public static void normalizeCompositeNode(Node node, Set modules, String schemaNodePath) { RestconfImpl restconf = RestconfImpl.getInstance(); ControllerContext.getInstance().setSchemas(TestUtils.loadSchemaContext(modules)); prepareMocksForRestconf(modules, restconf); - restconf.updateConfigurationData(schemaNodePath, compositeNode); + restconf.updateConfigurationData(schemaNodePath, node); } /** @@ -229,33 +251,30 @@ public final class TestUtils { controllerContext.setSchemas(TestUtils.loadSchemaContext(modules)); - when(mockedBrokerFacade.commitConfigurationDataPut(any(YangInstanceIdentifier.class), any(CompositeNode.class))) - .thenReturn( - new DummyFuture.Builder().rpcResult( - new DummyRpcResult.Builder().result(TransactionStatus.COMMITED) - .build()).build()); + when(mockedBrokerFacade.commitConfigurationDataPut(any(YangInstanceIdentifier.class), any(NormalizedNode.class))) + .thenReturn(mock(CheckedFuture.class)); restconf.setControllerContext(controllerContext); restconf.setBroker(mockedBrokerFacade); } - public static CompositeNode readInputToCnSn(String path, boolean dummyNamespaces, - MessageBodyReader reader) throws WebApplicationException { + public static Node readInputToCnSn(String path, boolean dummyNamespaces, + MessageBodyReader> reader) throws WebApplicationException { InputStream inputStream = TestUtils.class.getResourceAsStream(path); try { - CompositeNode compositeNode = reader.readFrom(null, null, null, null, null, inputStream); - assertTrue(compositeNode instanceof CompositeNodeWrapper); + final Node node = reader.readFrom(null, null, null, null, null, inputStream); + assertTrue(node instanceof CompositeNodeWrapper); if (dummyNamespaces) { try { - TestUtils.addDummyNamespaceToAllNodes((CompositeNodeWrapper) compositeNode); - return ((CompositeNodeWrapper) compositeNode).unwrap(); + TestUtils.addDummyNamespaceToAllNodes((CompositeNodeWrapper) node); + return ((CompositeNodeWrapper) node).unwrap(); } catch (URISyntaxException e) { LOG.error(e.getMessage()); assertTrue(e.getMessage(), false); } } - return compositeNode; + return node; } catch (IOException e) { LOG.error(e.getMessage()); assertTrue(e.getMessage(), false); @@ -263,21 +282,33 @@ public final class TestUtils { return null; } - public static CompositeNode readInputToCnSn(String path, MessageBodyReader reader) { +// public static Node readInputToCnSnNew(String path, MessageBodyReader> reader) throws WebApplicationException { +// InputStream inputStream = TestUtils.class.getResourceAsStream(path); +// try { +// return reader.readFrom(null, null, null, null, null, inputStream); +// } catch (IOException e) { +// LOG.error(e.getMessage()); +// assertTrue(e.getMessage(), false); +// } +// return null; +// } + + public static Node readInputToCnSn(String path, MessageBodyReader> reader) { return readInputToCnSn(path, false, reader); } - public static String writeCompNodeWithSchemaContextToOutput(CompositeNode compositeNode, Set modules, + public static String writeCompNodeWithSchemaContextToOutput(Node node, Set modules, DataSchemaNode dataSchemaNode, MessageBodyWriter messageBodyWriter) throws IOException, WebApplicationException { assertNotNull(dataSchemaNode); - assertNotNull("Composite node can't be null", compositeNode); + assertNotNull("Composite node can't be null", node); ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream(); ControllerContext.getInstance().setSchemas(loadSchemaContext(modules)); - messageBodyWriter.writeTo(new StructuredData(compositeNode, dataSchemaNode, null), null, null, null, null, + assertTrue(node instanceof CompositeNode); + messageBodyWriter.writeTo(new StructuredData((CompositeNode)node, dataSchemaNode, null), null, null, null, null, null, byteArrayOS); return byteArrayOS.toString(); @@ -312,4 +343,96 @@ public final class TestUtils { Matcher matcher = pattern.matcher(jsonOutput); return matcher.matches(); } + + public static NormalizedNode compositeNodeToDatastoreNormalizedNode(final CompositeNode compositeNode, + final DataSchemaNode schema) { + List> lst = new ArrayList>(); + lst.add(compositeNode); + if (schema instanceof ContainerSchemaNode) { + return CnSnToNormalizedNodeParserFactory.getInstance().getContainerNodeParser() + .parse(lst, (ContainerSchemaNode) schema); + } else if (schema instanceof ListSchemaNode) { + return CnSnToNormalizedNodeParserFactory.getInstance().getMapNodeParser() + .parse(lst, (ListSchemaNode) schema); + } + + LOG.error("Top level isn't of type container, list, leaf schema node but " + schema.getClass().getSimpleName()); + + throw new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "It wasn't possible to translate specified data to datastore readable form.")); + } + + public static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier(String localName, String namespace, + String revision) throws ParseException { + return new YangInstanceIdentifier.NodeIdentifier(QName.create(namespace, revision, localName)); + } + + public static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeIdentifierPredicate(String localName, + String namespace, String revision, Map keys) throws ParseException { + Map predicate = new HashMap<>(); + for (String key : keys.keySet()) { + predicate.put(QName.create(namespace, revision, key), keys.get(key)); + } + + return new YangInstanceIdentifier.NodeIdentifierWithPredicates( + + QName.create(namespace, revision, localName), predicate); + } + + public static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeIdentifierPredicate(String localName, + String namespace, String revision, String... keysAndValues) throws ParseException { + java.util.Date date = new SimpleDateFormat("yyyy-MM-dd").parse(revision); + if (keysAndValues.length % 2 != 0) { + new IllegalArgumentException("number of keys argument have to be divisible by 2 (map)"); + } + Map predicate = new HashMap<>(); + + int i = 0; + while (i < keysAndValues.length) { + predicate.put(QName.create(namespace, revision, keysAndValues[i++]), keysAndValues[i++]); + } + + return new YangInstanceIdentifier.NodeIdentifierWithPredicates(QName.create(namespace, revision, localName), + predicate); + } + + public static CompositeNode prepareCompositeNodeWithIetfInterfacesInterfacesData() { + CompositeNodeBuilder interfaceBuilder = ImmutableCompositeNode.builder(); + interfaceBuilder.addLeaf(buildQName("name", "dummy", "2014-07-29"), "eth0"); + interfaceBuilder.addLeaf(buildQName("type", "dummy", "2014-07-29"), "ethernetCsmacd"); + interfaceBuilder.addLeaf(buildQName("enabled", "dummy", "2014-07-29"), "false"); + interfaceBuilder.addLeaf(buildQName("description", "dummy", "2014-07-29"), "some interface"); + return interfaceBuilder.toInstance(); + } + + static NormalizedNode prepareNormalizedNodeWithIetfInterfacesInterfacesData() throws ParseException { + String ietfInterfacesDate = "2013-07-04"; + CollectionNodeBuilder intface = ImmutableMapNodeBuilder.create(); + String namespace = "urn:ietf:params:xml:ns:yang:ietf-interfaces"; + intface.withNodeIdentifier(getNodeIdentifier("interface", namespace, ietfInterfacesDate)); + DataContainerNodeAttrBuilder mapEntryNode = ImmutableMapEntryNodeBuilder.create(); + + Map predicates = new HashMap<>(); + predicates.put("name", "eth0"); + + mapEntryNode.withNodeIdentifier(getNodeIdentifierPredicate("interface", namespace, ietfInterfacesDate, + predicates)); + mapEntryNode + .withChild(new ImmutableLeafNodeBuilder() + .withNodeIdentifier(getNodeIdentifier("name", namespace, ietfInterfacesDate)).withValue("eth0") + .build()); + mapEntryNode.withChild(new ImmutableLeafNodeBuilder() + .withNodeIdentifier(getNodeIdentifier("type", namespace, ietfInterfacesDate)) + .withValue("ethernetCsmacd").build()); + mapEntryNode.withChild(new ImmutableLeafNodeBuilder() + .withNodeIdentifier(getNodeIdentifier("enabled", namespace, ietfInterfacesDate)) + .withValue(Boolean.FALSE).build()); + mapEntryNode.withChild(new ImmutableLeafNodeBuilder() + .withNodeIdentifier(getNodeIdentifier("description", namespace, ietfInterfacesDate)) + .withValue("some interface").build()); + + intface.withChild(mapEntryNode.build()); + + return intface.build(); + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java new file mode 100644 index 0000000000..3c954f840a --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java @@ -0,0 +1,101 @@ +/* + * 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.mockito.Matchers.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.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; +import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; +import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter; +import org.opendaylight.controller.sal.streams.listeners.Notificator; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder; +import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; + +public class URIParametersParsing { + + private RestconfImpl restconf; + private BrokerFacade mockedBrokerFacade; + + @Before + public void init() throws FileNotFoundException { + restconf = RestconfImpl.getInstance(); + mockedBrokerFacade = mock(BrokerFacade.class); + ControllerContext controllerContext = ControllerContext.getInstance(); + controllerContext.setSchemas(TestUtils.loadSchemaContext("/datastore-and-scope-specification")); + restconf.setControllerContext(controllerContext); + restconf.setBroker(mockedBrokerFacade); + } + + @Test + public void resolveURIParametersConcreteValues() { + resolveURIParameters("OPERATIONAL", "SUBTREE", LogicalDatastoreType.OPERATIONAL, DataChangeScope.SUBTREE); + } + + @Test + public void resolveURIParametersDefaultValues() { + resolveURIParameters(null, null, LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE); + } + + private void resolveURIParameters(final String datastore, final String scope, + final LogicalDatastoreType datastoreExpected, final DataChangeScope scopeExpected) { + + 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); + + UriInfo mockedUriInfo = mock(UriInfo.class); + MultivaluedMap 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); + + UriBuilder uriBuilder = UriBuilder.fromUri("www.whatever.com"); + when(mockedUriInfo.getAbsolutePathBuilder()).thenReturn(uriBuilder); + + restconf.invokeRpc("sal-remote:create-data-change-event-subscription", prepareRpcNode(datastore, scope), + mockedUriInfo); + + ListenerAdapter listener = Notificator.getListenerFor("opendaylight-inventory:nodes/datastore=" + + datastoreValue + "/scope=" + scopeValue); + assertNotNull(listener); + + } + + private CompositeNode prepareRpcNode(final String datastore, final String scope) { + CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); + inputBuilder.setQName(QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", + "2014-01-14", "input")); + inputBuilder.addLeaf( + QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "2014-01-14", "path"), + YangInstanceIdentifier.builder().node(QName.create("urn:opendaylight:inventory", "2013-08-19", "nodes")).build()); + inputBuilder.addLeaf(QName.create("urn:sal:restconf:event:subscription", "2014-7-8", "datastore"), datastore); + inputBuilder.addLeaf(QName.create("urn:sal:restconf:event:subscription", "2014-7-8", "scope"), scope); + return inputBuilder.toInstance(); + } +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java index 655aba267f..ed871bb527 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java @@ -14,6 +14,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.base.Optional; import com.google.common.collect.Iterables; import java.io.FileNotFoundException; import java.util.Set; @@ -21,8 +22,8 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.core.api.mount.MountService; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode; @@ -153,7 +154,7 @@ public class URITest { } public void initMountService(final boolean withSchema) { - MountService mountService = mock(MountService.class); + DOMMountPointService mountService = mock(DOMMountPointService.class); controllerContext.setMountService(mountService); BrokerFacade brokerFacade = mock(BrokerFacade.class); RestconfImpl restconfImpl = RestconfImpl.getInstance(); @@ -162,12 +163,12 @@ public class URITest { Set modules2 = TestUtils.loadModulesFrom("/test-config-data/yang2"); SchemaContext schemaContext2 = TestUtils.loadSchemaContext(modules2); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); if (withSchema) { when(mountInstance.getSchemaContext()).thenReturn(schemaContext2); } else { when(mountInstance.getSchemaContext()).thenReturn(null); } - when(mountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + when(mountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java index f4e869f99f..23e868c8b2 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java @@ -26,6 +26,7 @@ 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.Node; import org.opendaylight.yangtools.yang.data.api.SimpleNode; public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader { @@ -37,32 +38,44 @@ public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSch @Test public void loadXmlToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata.xml", + Node node = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE); + + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyListPredicate(cnSn); } @Test public void loadXmlLeafListToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata_leaf_list.xml", + Node node = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata_leaf_list.xml", XmlToCompositeNodeProvider.INSTANCE); + + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyLeafListPredicate(cnSn); } @Test public void loadJsonToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata.json", + Node node = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata.json", JsonToCompositeNodeProvider.INSTANCE); + + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyListPredicate(cnSn); } @Test public void loadJsonLeafListToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata_leaf_list.json", + Node node = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata_leaf_list.json", JsonToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; + TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyLeafListPredicate(cnSn); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java index 483d90da0d..1c8e53e69f 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.URISyntaxException; @@ -29,15 +30,22 @@ public class XmlAndJsonToCnSnLeafRefTest extends YangAndXmlAndDataSchemaLoader { @Test public void loadXmlToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/leafref/xml/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE); + Node node = TestUtils.readInputToCnSn("/leafref/xml/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE); + + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; + TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyContPredicate(cnSn, "/ns:cont/ns:lf1", "/cont/lf1", "/ns:cont/ns:lf1", "../lf1"); } @Test public void loadJsonToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/leafref/json/jsondata.json", + Node node = TestUtils.readInputToCnSn("/leafref/json/jsondata.json", JsonToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; + TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyContPredicate(cnSn, "/leafref-module:cont/leafref-module:lf1", "/leafref-module:cont/leafref-module:lf1", "/referenced-module:cont/referenced-module:lf1", "/leafref-module:cont/leafref-module:lf1"); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java index 70f0f050dc..121a3865bd 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java @@ -32,6 +32,9 @@ import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; public class RestStream extends JerseyTest { @@ -68,17 +71,20 @@ public class RestStream extends JerseyTest { public void testCallRpcCallGet() throws UnsupportedEncodingException, InterruptedException { String uri = "/operations/sal-remote:create-data-change-event-subscription"; Response responseWithStreamName = post(uri, MediaType.APPLICATION_XML, getRpcInput()); - String xmlResponse = responseWithStreamName.readEntity(String.class); + Document xmlResponse = responseWithStreamName.readEntity(Document.class); assertNotNull(xmlResponse); - assertTrue(xmlResponse - .contains("ietf-interfaces:interfaces/ietf-interfaces:interface/eth0")); + Element outputElement = xmlResponse.getDocumentElement(); + assertEquals("output",outputElement.getLocalName()); - uri = "/streams/stream/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0"; + Node streamNameElement = outputElement.getFirstChild(); + assertEquals("stream-name",streamNameElement.getLocalName()); + assertEquals("ietf-interfaces:interfaces/ietf-interfaces:interface/eth0/datastore=CONFIGURATION/scope=BASE",streamNameElement.getTextContent()); + + uri = "/streams/stream/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0/datastore=CONFIGURATION/scope=BASE"; Response responseWithRedirectionUri = get(uri, MediaType.APPLICATION_XML); final URI websocketServerUri = responseWithRedirectionUri.getLocation(); assertNotNull(websocketServerUri); - assertEquals(websocketServerUri.toString(), - "http://localhost:8181/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0"); + assertTrue(websocketServerUri.toString().matches(".*http://localhost:[\\d]+/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0.*")); } private Response post(String uri, String mediaType, String data) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java index 5a5a621d93..e992e1214e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java @@ -8,12 +8,14 @@ package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.util.Set; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.model.api.Module; public class XmlAugmentedElementToCnSnTest { @@ -25,12 +27,15 @@ public class XmlAugmentedElementToCnSnTest { } private void loadAndNormalizeData(String xmlPath, String yangPath, String topLevelElementName, String moduleName) { - CompositeNode compNode = TestUtils.readInputToCnSn(xmlPath, false, XmlToCompositeNodeProvider.INSTANCE); - assertNotNull(compNode); + Node node = TestUtils.readInputToCnSn(xmlPath, false, + XmlToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; + Set modules = TestUtils.loadModulesFrom(yangPath); assertNotNull(modules); - TestUtils.normalizeCompositeNode(compNode, modules, topLevelElementName + ":" + moduleName); + TestUtils.normalizeCompositeNode(cnSn, modules, topLevelElementName + ":" + moduleName); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java index 6c11bc1861..1c62b7fbdb 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java @@ -33,8 +33,11 @@ public class XmlLeafrefToCnSnTest { */ @Test public void testXmlDataContainer() { - CompositeNode compNode = TestUtils.readInputToCnSn("/xml-to-cnsn/data-container.xml", false, + Node node = TestUtils.readInputToCnSn("/xml-to-cnsn/data-container.xml", false, XmlToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode compNode = (CompositeNode)node; + assertNotNull(compNode); Set modules = TestUtils.loadModulesFrom("/xml-to-cnsn/data-container-yang"); @@ -76,9 +79,11 @@ public class XmlLeafrefToCnSnTest { @Test public void testXmlDataList() { - CompositeNode compNode = TestUtils.readInputToCnSn("/xml-to-cnsn/data-list.xml", false, + Node node = TestUtils.readInputToCnSn("/xml-to-cnsn/data-list.xml", false, XmlToCompositeNodeProvider.INSTANCE); - assertNotNull(compNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compNode = (CompositeNode)node; + Set modules = TestUtils.loadModulesFrom("/xml-to-cnsn/data-list-yang"); assertNotNull(modules); @@ -93,22 +98,22 @@ public class XmlLeafrefToCnSnTest { CompositeNode lst1_1 = null; CompositeNode lst1_2 = null; int loopCount = 0; - for (Node node : compNode.getValue()) { - if (node.getNodeType().getLocalName().equals("lf1")) { - assertEquals(nameSpaceList, node.getNodeType().getNamespace().toString()); - assertTrue(node instanceof SimpleNode); - assertEquals("lf1", node.getValue()); + for (Node nd : compNode.getValue()) { + if (nd.getNodeType().getLocalName().equals("lf1")) { + assertEquals(nameSpaceList, nd.getNodeType().getNamespace().toString()); + assertTrue(nd instanceof SimpleNode); + assertEquals("lf1", nd.getValue()); } else { - assertTrue(node instanceof CompositeNode); + assertTrue(nd instanceof CompositeNode); switch (loopCount++) { case 0: - lst1_1 = (CompositeNode) node; + lst1_1 = (CompositeNode) nd; break; case 1: - lst1_2 = (CompositeNode) node; + lst1_2 = (CompositeNode) nd; break; } - assertEquals(nameSpaceCont, node.getNodeType().getNamespace().toString()); + assertEquals(nameSpaceCont, nd.getNodeType().getNamespace().toString()); } } // lst1_1 @@ -118,15 +123,15 @@ public class XmlLeafrefToCnSnTest { // lst1_2 SimpleNode lflst11 = null; CompositeNode cont11 = null; - for (Node node : lst1_2.getValue()) { - String nodeName = node.getNodeType().getLocalName(); + for (Node nd : lst1_2.getValue()) { + String nodeName = nd.getNodeType().getLocalName(); if (nodeName.equals("lflst11")) { - assertTrue(node instanceof SimpleNode); - lflst11 = (SimpleNode) node; + assertTrue(nd instanceof SimpleNode); + lflst11 = (SimpleNode) nd; } else if (nodeName.equals("cont11")) { - assertTrue(node instanceof CompositeNode); - cont11 = (CompositeNode) node; + assertTrue(nd instanceof CompositeNode); + cont11 = (CompositeNode) nd; } assertEquals(nameSpaceCont, compNode.getNodeType().getNamespace().toString()); } @@ -144,32 +149,35 @@ public class XmlLeafrefToCnSnTest { @Test public void testXmlEmptyData() { - CompositeNode compNode = TestUtils.readInputToCnSn("/xml-to-cnsn/empty-data.xml", true, + Node node = TestUtils.readInputToCnSn("/xml-to-cnsn/empty-data.xml", true, XmlToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode compNode = (CompositeNode)node; + assertEquals("cont", compNode.getNodeType().getLocalName()); SimpleNode lf1 = null; SimpleNode lflst1_1 = null; SimpleNode lflst1_2 = null; CompositeNode lst1 = null; int lflst1Count = 0; - for (Node node : compNode.getValue()) { - if (node.getNodeType().getLocalName().equals("lf1")) { - assertTrue(node instanceof SimpleNode); - lf1 = (SimpleNode) node; - } else if (node.getNodeType().getLocalName().equals("lflst1")) { - assertTrue(node instanceof SimpleNode); + for (Node nd : compNode.getValue()) { + if (nd.getNodeType().getLocalName().equals("lf1")) { + assertTrue(nd instanceof SimpleNode); + lf1 = (SimpleNode) nd; + } else if (nd.getNodeType().getLocalName().equals("lflst1")) { + assertTrue(nd instanceof SimpleNode); switch (lflst1Count++) { case 0: - lflst1_1 = (SimpleNode) node; + lflst1_1 = (SimpleNode) nd; break; case 1: - lflst1_2 = (SimpleNode) node; + lflst1_2 = (SimpleNode) nd; break; } - } else if (node.getNodeType().getLocalName().equals("lst1")) { - assertTrue(node instanceof CompositeNode); - lst1 = (CompositeNode) node; + } else if (nd.getNodeType().getLocalName().equals("lst1")) { + assertTrue(nd instanceof CompositeNode); + lst1 = (CompositeNode) nd; } } @@ -317,8 +325,10 @@ public class XmlLeafrefToCnSnTest { private void testIdentityrefToCnSn(final String xmlPath, final String yangPath, final String moduleName, final String schemaName, final int moduleCount, final String resultLocalName, final String resultNamespace) { - CompositeNode compositeNode = TestUtils.readInputToCnSn(xmlPath, false, XmlToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + Node node = TestUtils.readInputToCnSn(xmlPath, false, XmlToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; + Set modules = TestUtils.loadModulesFrom(yangPath); assertEquals(moduleCount, modules.size()); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java index e2621d635b..d0af29e913 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java @@ -32,9 +32,12 @@ public class XmlToCnSnTest extends YangAndXmlAndDataSchemaLoader { @Test public void testXmlLeafrefToCnSn() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/xml-to-cnsn/leafref/xml/data.xml", false, + Node node = TestUtils.readInputToCnSn("/xml-to-cnsn/leafref/xml/data.xml", false, XmlToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; + + assertNotNull(dataSchemaNode); TestUtils.normalizeCompositeNode(compositeNode, modules, schemaNodePath); @@ -58,10 +61,10 @@ public class XmlToCnSnTest extends YangAndXmlAndDataSchemaLoader { @Test public void testXmlBlankInput() throws Exception { InputStream inputStream = new ByteArrayInputStream("".getBytes()); - CompositeNode compositeNode = XmlToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, - inputStream); + Node node = + XmlToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, inputStream); - assertNull(compositeNode); + assertNull( node ); } @Test @@ -72,10 +75,10 @@ public class XmlToCnSnTest extends YangAndXmlAndDataSchemaLoader { return false; } }; - CompositeNode compositeNode = XmlToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, - inputStream); + Node node = + XmlToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, inputStream); - assertNull(compositeNode); + assertNull( node ); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/opendaylight-inventory.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/opendaylight-inventory.yang new file mode 100644 index 0000000000..e4247bee1e --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/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/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang new file mode 100644 index 0000000000..83934568cc --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang @@ -0,0 +1,31 @@ +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-7-8" { + } + + 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; + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote@2014-01-14.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote@2014-01-14.yang new file mode 100644 index 0000000000..d12e252711 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/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 "; + + 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 -- 2.36.6