<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ <version>0.5.9-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-util</artifactId>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
+ <version>2.2.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<version>3.0.4.Final</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ <version>${yang.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.2.4</version>
+ </dependency>
<!-- Testing Dependencies -->
<dependency>
<scope>test</scope>
</dependency>
<dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-impl</artifactId>
- <version>${yang.version}</version>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+ <version>2.4</version>
<scope>test</scope>
</dependency>
</dependencies>
* 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;
+package org.opendaylight.controller.sal.rest.api;
import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import org.opendaylight.controller.sal.restconf.impl.StructuredData;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
/**
@GET
@Path("/datastore/{identifier}")
- @Produces({API+XML})
- public Object readData(@PathParam("identifier") String identifier);
+ @Produces({API+JSON,API+XML})
+ public StructuredData readData(@PathParam("identifier") String identifier);
@PUT
@Path("/datastore/{identifier}")
- @Produces({API+XML})
+ @Produces({API+JSON,API+XML})
public Object createConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
@POST
@Path("/datastore/{identifier}")
- @Produces({API+XML})
+ @Produces({API+JSON,API+XML})
public Object updateConfigurationData(@PathParam("identifier") String identifier, CompositeNode payload);
@GET
@Path("/modules")
- @Produces(API+XML)
+ @Produces({API+JSON,API+XML})
public Object getModules();
@POST
@Path("/operations/{identifier}")
- @Produces(API+XML)
- public Object invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
+ @Produces({API+JSON,API+XML})
+ public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
}
--- /dev/null
+package org.opendaylight.controller.sal.rest.impl;
+
+import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+@Provider
+@Consumes({API+RestconfService.JSON})
+public enum JsonToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
+ INSTANCE;
+
+ @Override
+ public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public CompositeNode readFrom(Class<CompositeNode> type, Type genericType, Annotation[] annotations,
+ MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+ throws IOException, WebApplicationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.rest.impl;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.ws.rs.core.Application;
+
+import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+
+public class RestconfApplication extends Application {
+
+ @Override
+ public Set<Object> getSingletons() {
+ Set<Object> singletons = new HashSet<>();
+ ControllerContext controllerContext = ControllerContext.getInstance();
+ BrokerFacade brokerFacade = BrokerFacade.getInstance();
+ RestconfImpl restconfImpl = RestconfImpl.getInstance();
+ restconfImpl.setBroker(brokerFacade);
+ restconfImpl.setControllerContext(controllerContext);
+ singletons.add(controllerContext);
+ singletons.add(brokerFacade);
+ singletons.add(restconfImpl);
+ singletons.add(XmlToCompositeNodeProvider.INSTANCE);
+ singletons.add(StructuredDataToXmlProvider.INSTANCE);
+ return singletons;
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.rest.impl;
+
+import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.restconf.impl.StructuredData;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+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.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
+
+import com.google.gson.stream.JsonWriter;
+
+@Provider
+@Produces({ API + RestconfService.JSON })
+public enum StructuredDataToJsonProvider implements MessageBodyWriter<StructuredData> {
+ INSTANCE;
+
+ @Override
+ public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public long getSize(StructuredData t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public void writeTo(StructuredData t, Class<?> type, Type genericType, Annotation[] annotations,
+ MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
+ throws IOException, WebApplicationException {
+ JsonWriter writer = new JsonWriter(new OutputStreamWriter(entityStream, "UTF-8"));
+ writer.setIndent(" ");
+ writer.beginObject();
+ convertNodeToJsonAccordingToSchema(writer, t.getData(), t.getSchema());
+ writer.endObject();
+ }
+
+ private void convertNodeToJsonAccordingToSchema(JsonWriter writer, Node<?> node, DataSchemaNode dataSchemaNode) throws IOException {
+ if (node instanceof CompositeNode) {
+ if (!(dataSchemaNode instanceof DataNodeContainer)) {
+ throw new IllegalStateException("CompositeNode should be represented as DataNodeContainer");
+ }
+ if (dataSchemaNode instanceof ContainerSchemaNode) {
+ writer.name(node.getNodeType().getLocalName());
+ writer.beginObject();
+ String listName = "";
+ for (Node<?> n : ((CompositeNode) node).getChildren()) {
+ DataSchemaNode foundDataSchemaNode = findSchemaForNode(n, ((DataNodeContainer) dataSchemaNode).getChildNodes());
+ if (foundDataSchemaNode instanceof ListSchemaNode) {
+ if (listName.equals(n.getNodeType().getLocalName())) {
+ continue;
+ }
+ listName = n.getNodeType().getLocalName();
+ }
+ convertNodeToJsonAccordingToSchema(writer, n, foundDataSchemaNode);
+ }
+ writer.endObject();
+ } else if (dataSchemaNode instanceof ListSchemaNode) {
+ writer.name(node.getNodeType().getLocalName());
+ writer.beginArray();
+ List<Node<?>> nodeSiblings = node.getParent().getChildren();
+ for (Node<?> nodeSibling : nodeSiblings) {
+ if (nodeSibling.getNodeType().getLocalName().equals(node.getNodeType().getLocalName())) {
+ DataSchemaNode schemaForNodeSibling = findSchemaForNode(nodeSibling,
+ ((DataNodeContainer) dataSchemaNode.getParent()).getChildNodes());
+ writer.beginObject();
+ for (Node<?> child : ((CompositeNode) nodeSibling).getChildren()) {
+ DataSchemaNode schemaForChild = findSchemaForNode(child,
+ ((DataNodeContainer) schemaForNodeSibling).getChildNodes());
+ convertNodeToJsonAccordingToSchema(writer, child, schemaForChild);
+ }
+ writer.endObject();
+ }
+ }
+ writer.endArray();
+ }
+ } else if (node instanceof SimpleNode<?>) {
+ if (!(dataSchemaNode instanceof LeafSchemaNode)) {
+ throw new IllegalStateException("SimpleNode should should be represented as LeafSchemaNode");
+ }
+ writeLeaf(writer, (LeafSchemaNode) dataSchemaNode, (SimpleNode<?>) node);
+ }
+ }
+
+ private DataSchemaNode findSchemaForNode(Node<?> node, Set<DataSchemaNode> dataSchemaNode) {
+ for (DataSchemaNode dsn : dataSchemaNode) {
+ if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) {
+ return dsn;
+ }
+ }
+ return null;
+ }
+
+ private void writeLeaf(JsonWriter writer, LeafSchemaNode leafSchemaNode, SimpleNode<?> data) throws IOException {
+ TypeDefinition<?> type = leafSchemaNode.getType();
+
+ writer.name(data.getNodeType().getLocalName());
+
+ if (type instanceof DecimalTypeDefinition) {
+ writer.value((Double.valueOf((String) data.getValue())).doubleValue());
+ } else if (type instanceof IntegerTypeDefinition) {
+ writer.value((Integer.valueOf((String) data.getValue())).intValue());
+ } else if (type instanceof EmptyTypeDefinition) {
+ writer.value("[null]");
+ } else {
+ writer.value(String.valueOf(data.getValue()));
+ }
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.rest.impl;
+
+import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.restconf.impl.StructuredData;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+@Provider
+@Produces({API+RestconfService.XML})
+public enum StructuredDataToXmlProvider implements MessageBodyWriter<StructuredData> {
+ INSTANCE;
+
+ private final static Logger logger = LoggerFactory.getLogger(StructuredDataToXmlProvider.class);
+
+ @Override
+ public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return true;
+ }
+
+ @Override
+ public long getSize(StructuredData t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return -1;
+ }
+
+ @Override
+ public void writeTo(StructuredData t, Class<?> type, Type genericType, Annotation[] annotations,
+ MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
+ throws IOException, WebApplicationException {
+ CompositeNode data = t.getData();
+ Document domTree = NodeUtils.buildShadowDomTree(data);
+
+ try {
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+ transformer.transform(new DOMSource(domTree), new StreamResult(entityStream));
+ } catch (TransformerException e) {
+ logger.error("Error during translation of Document to OutputStream", e);
+ new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).build());
+ }
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.rest.impl;
+
+import static org.opendaylight.controller.sal.restconf.impl.MediaTypes.API;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import javax.xml.stream.XMLStreamException;
+
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Provider
+@Consumes({API+RestconfService.XML})
+public enum XmlToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
+ INSTANCE;
+
+ private final static Logger logger = LoggerFactory.getLogger(XmlToCompositeNodeProvider.class);
+
+ @Override
+ public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return true;
+ }
+
+ @Override
+ public CompositeNode readFrom(Class<CompositeNode> type, Type genericType, Annotation[] annotations,
+ MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+ throws IOException, WebApplicationException {
+ try {
+ Node<?> node = XmlTreeBuilder.buildDataTree(entityStream);
+ if (node instanceof SimpleNode) {
+ logger.info("Node is SimpleNode");
+ throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
+ .entity("XML should start with XML element that contains 1..N XML child elements.").build());
+ }
+ return (CompositeNode) node;
+ } catch (XMLStreamException e) {
+ logger.info("Error during translation of InputStream to Node\n" + e.getMessage());
+ throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
+ .entity(e.getMessage()).build());
+ }
+ }
+
+}
import org.opendaylight.yangtools.yang.common.RpcResult
import org.opendaylight.yangtools.yang.data.api.CompositeNode
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import static org.opendaylight.controller.sal.restconf.impl.BrokerFacade.*
class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
+ val static BrokerFacade INSTANCE = new BrokerFacade
+
@Property
private ConsumerSession context;
@Property
private DataBrokerService dataService;
+
+ private new() {
+ if (INSTANCE != null) {
+ throw new IllegalStateException("Already instantiated");
+ }
+ }
+
+ def static BrokerFacade getInstance() {
+ return INSTANCE
+ }
override readConfigurationData(InstanceIdentifier path) {
return dataService.readConfigurationData(path);
transaction.putConfigurationData(path, payload);
return transaction.commit()
}
-
+
}
class ControllerContext {
+ val static ControllerContext INSTANCE = new ControllerContext
+
val static NULL_VALUE = "null"
-
+
@Property
SchemaContext schemas;
private val BiMap<URI, String> uriToModuleName = HashBiMap.create();
private val Map<String, URI> moduleNameToUri = uriToModuleName.inverse();
+ private new() {
+ if (INSTANCE != null) {
+ throw new IllegalStateException("Already instantiated");
+ }
+ }
+
+ static def getInstance() {
+ return INSTANCE
+ }
+
public def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) {
val ret = InstanceIdentifier.builder();
val pathArgs = restconfInstance.split("/");
package org.opendaylight.controller.sal.restconf.impl
-import org.opendaylight.controller.sal.core.api.model.SchemaService
import org.opendaylight.yangtools.yang.data.api.CompositeNode
-
-import static com.google.common.base.Preconditions.*
+import org.opendaylight.controller.sal.rest.api.RestconfService
class RestconfImpl implements RestconfService {
+
+ val static RestconfImpl INSTANCE = new RestconfImpl
@Property
BrokerFacade broker
@Property
extension ControllerContext controllerContext
-
- val JsonMapper jsonMapper = new JsonMapper;
-
- def init(SchemaService schemaService) {
- checkState(broker !== null)
- checkState(controllerContext !== null)
- checkState(schemaService !== null)
- controllerContext.schemas = schemaService.globalContext
+
+ private new() {
+ if (INSTANCE != null) {
+ throw new IllegalStateException("Already instantiated");
+ }
+ }
+
+ static def getInstance() {
+ return INSTANCE
}
override readAllData() {
- return broker.readOperationalData("".removePrefixes.toInstanceIdentifier.getInstanceIdentifier);
+// return broker.readOperationalData("".toInstanceIdentifier.getInstanceIdentifier);
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override getModules() {
}
override readData(String identifier) {
- val instanceIdentifierWithSchemaNode = identifier.removePrefixes.toInstanceIdentifier
+ val instanceIdentifierWithSchemaNode = identifier.toInstanceIdentifier
val data = broker.readOperationalData(instanceIdentifierWithSchemaNode.getInstanceIdentifier);
- jsonMapper.convert(instanceIdentifierWithSchemaNode.getSchemaNode, data)
+ return new StructuredData(data, instanceIdentifierWithSchemaNode.schemaNode)
}
override createConfigurationData(String identifier, CompositeNode payload) {
- return broker.commitConfigurationDataCreate(identifier.removePrefixes.toInstanceIdentifier.getInstanceIdentifier, payload);
+// return broker.commitConfigurationDataCreate(identifier.toInstanceIdentifier.getInstanceIdentifier, payload);
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override updateConfigurationData(String identifier, CompositeNode payload) {
- return broker.commitConfigurationDataCreate(identifier.removePrefixes.toInstanceIdentifier.getInstanceIdentifier, payload);
+// return broker.commitConfigurationDataCreate(identifier.toInstanceIdentifier.getInstanceIdentifier, payload);
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override invokeRpc(String identifier, CompositeNode payload) {
- val rpcResult = broker.invokeRpc(identifier.removePrefixes.toRpcQName, payload);
- jsonMapper.convert(identifier.removePrefixes.toInstanceIdentifier.getSchemaNode, rpcResult.result);
- }
-
- private def String removePrefixes(String path) {
- return path;
+ val rpcResult = broker.invokeRpc(identifier.toRpcQName, payload);
+ return new StructuredData(rpcResult.result, identifier.toInstanceIdentifier.getSchemaNode)
}
}
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl;
+
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+public class StructuredData {
+
+ private final CompositeNode data;
+ private final DataSchemaNode schema;
+
+ public StructuredData(CompositeNode data, DataSchemaNode schema) {
+ this.data = data;
+ this.schema = schema;
+ }
+
+ public CompositeNode getData() {
+ return data;
+ }
+
+ public DataSchemaNode getSchema() {
+ return schema;
+ }
+
+}
public class ControllerContextTest {
- private static final ControllerContext controllerContext = new ControllerContext();
+ private static final ControllerContext controllerContext = ControllerContext.getInstance();
@BeforeClass
public static void init() throws FileNotFoundException {
assertTrue(instanceIdentifier.getSchemaNode() instanceof ContainerSchemaNode);
assertEquals(2, ((ContainerSchemaNode)instanceIdentifier.getSchemaNode()).getChildNodes().size());
}
-
+
@Test
public void testToInstanceIdentifierChoice() throws FileNotFoundException {
InstanceIdWithSchemaNode instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:food/beer");
+++ /dev/null
-package org.opendaylight.controller.sal.restconf.impl.test;
-
-import static org.junit.Assert.*;
-
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.util.Set;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
-import org.opendaylight.controller.sal.restconf.impl.JsonMapper;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-
-public class JsonMapperTest {
-
- private static final ControllerContext controllerContext = new ControllerContext();
-
- @BeforeClass
- public static void init() throws FileNotFoundException {
- Set<Module> allModules = TestUtils.loadModules(JsonMapperTest.class.getResource("/full-versions/yangs").getPath());
- SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules);
- controllerContext.setSchemas(schemaContext);
- }
-
- @Test
- public void test() throws FileNotFoundException {
- InputStream xmlStream = JsonMapperTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
- CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream);
- DataSchemaNode loadedSchemaNode = controllerContext.toInstanceIdentifier("ietf-interfaces:interfaces/interface/eth0").getSchemaNode();
- JsonMapper jsonMapper = new JsonMapper();
- String json = jsonMapper.convert(loadedSchemaNode, loadedCompositeNode);
- }
-
-}
public class RestconfImplTest {
- private static final RestconfImpl restconfImpl = new RestconfImpl();
+ private static final RestconfImpl restconfImpl = RestconfImpl.getInstance();
@BeforeClass
public static void init() throws FileNotFoundException {
Set<Module> allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs").getPath());
SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules);
- ControllerContext controllerContext = new ControllerContext();
+ ControllerContext controllerContext = ControllerContext.getInstance();
controllerContext.setSchemas(schemaContext);
restconfImpl.setControllerContext(controllerContext);
}
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.mockito.Mockito.*;
+import static org.junit.Assert.*;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+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.MediaTypes;
+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.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import com.google.common.base.Charsets;
+
+public class XmlProvidersTest extends JerseyTest {
+
+ private static ControllerContext controllerContext;
+ private static BrokerFacade brokerFacade;
+ private static RestconfImpl restconfImpl;
+
+ @BeforeClass
+ public static void init() {
+ Set<Module> allModules = null;
+ try {
+ allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs").getPath());
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules);
+ controllerContext = ControllerContext.getInstance();
+ controllerContext.setSchemas(schemaContext);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.getInstance();
+ restconfImpl.setBroker(brokerFacade);
+ restconfImpl.setControllerContext(controllerContext);
+ }
+
+// @Before
+ public void logs() {
+ List<LogRecord> loggedRecords = getLoggedRecords();
+ for (LogRecord l : loggedRecords) {
+ System.out.println(l.getMessage());
+ }
+ }
+
+ @Test
+ public void testStructuredDataToXmlProvider() throws FileNotFoundException {
+ URI uri = null;
+ try {
+ uri = new URI("/restconf/datastore/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString());
+ } catch (UnsupportedEncodingException | URISyntaxException e) {
+ e.printStackTrace();
+ }
+
+ InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+ CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream);
+ when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode);
+
+ Response response = target(uri.toASCIIString()).request(MediaTypes.API+RestconfService.XML).get();
+ assertEquals(200, response.getStatus());
+ }
+
+ @Test
+ public void testXmlToCompositeNodeProvider() throws ParserConfigurationException, SAXException, IOException {
+ URI uri = null;
+ try {
+ uri = new URI("/restconf/operations/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString());
+ } catch (UnsupportedEncodingException | URISyntaxException e) {
+ e.printStackTrace();
+ }
+ InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+ final CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream);
+ when(brokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class))).thenReturn(new RpcResult<CompositeNode>() {
+
+ @Override
+ public boolean isSuccessful() {
+ return true;
+ }
+
+ @Override
+ public CompositeNode getResult() {
+ return loadedCompositeNode;
+ }
+
+ @Override
+ public Collection<RpcError> getErrors() {
+ return null;
+ }
+ });
+
+ DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
+ xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+ Document doc = docBuilder.parse(xmlStream);
+
+ Response response = target(uri.toASCIIString()).request(MediaTypes.API+RestconfService.XML).post(Entity.entity(TestUtils.getDocumentInPrintableForm(doc), new MediaType("application","vnd.yang.api+xml")));
+ assertEquals(200, response.getStatus());
+ }
+
+ @Test
+ public void testXmlToCompositeNodeProviderExceptions() {
+ URI uri = null;
+ try {
+ uri = new URI("/restconf/operations/" + URLEncoder.encode("ietf-interfaces:interfaces/interface/eth0", Charsets.US_ASCII.name()).toString());
+ } catch (UnsupportedEncodingException | URISyntaxException e) {
+ e.printStackTrace();
+ }
+
+ Response response = target(uri.toASCIIString()).request(MediaTypes.API + RestconfService.XML).post(
+ Entity.entity("<SimpleNode/>", new MediaType("application", "vnd.yang.api+xml")));
+ assertEquals(400, response.getStatus());
+
+ response = target(uri.toASCIIString()).request(MediaTypes.API + RestconfService.XML).post(
+ Entity.entity("<SimpleNode>", new MediaType("application", "vnd.yang.api+xml")));
+ assertEquals(400, response.getStatus());
+ }
+
+ @Override
+ protected Application configure() {
+ enable(TestProperties.LOG_TRAFFIC);
+ enable(TestProperties.DUMP_ENTITY);
+ enable(TestProperties.RECORD_LOG_LEVEL);
+ set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE);
+ return resourceConfig;
+ }
+
+}