*/
package org.opendaylight.controller.sal.rest.impl;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
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.stream.FactoryConfigurationError;
import org.opendaylight.controller.sal.rest.api.RestconfService;
import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
-import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
@Provider
@Produces({ Draft02.MediaTypes.API + RestconfService.XML, Draft02.MediaTypes.DATA + RestconfService.XML,
- Draft02.MediaTypes.OPERATION + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
-
+ Draft02.MediaTypes.OPERATION + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public class NormalizedNodeXmlBodyWriter implements MessageBodyWriter<NormalizedNodeContext> {
-
private static final XMLOutputFactory XML_FACTORY;
static {
- XML_FACTORY = XMLOutputFactory.newFactory();
+ XML_FACTORY = XMLOutputFactory.newFactory();
XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
}
-
@Override
- public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
+ public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+ final MediaType mediaType) {
return type.equals(NormalizedNodeContext.class);
}
@Override
- public long getSize(final NormalizedNodeContext t, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
+ public long getSize(final NormalizedNodeContext t, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
return -1;
}
@Override
- public void writeTo(final NormalizedNodeContext t, final Class<?> type, final Type genericType, final Annotation[] annotations,
- final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream)
- throws IOException, WebApplicationException {
- InstanceIdentifierContext pathContext = t.getInstanceIdentifierContext();
+ public void writeTo(final NormalizedNodeContext t, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream) throws IOException,
+ WebApplicationException {
+ final InstanceIdentifierContext pathContext = t.getInstanceIdentifierContext();
if (t.getData() == null) {
- throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
+ return;
}
XMLStreamWriter xmlWriter;
try {
xmlWriter = XML_FACTORY.createXMLStreamWriter(entityStream);
- } catch (XMLStreamException e) {
+ } catch (final XMLStreamException e) {
throw new IllegalStateException(e);
- } catch (FactoryConfigurationError e) {
+ } catch (final FactoryConfigurationError e) {
throw new IllegalStateException(e);
}
NormalizedNode<?, ?> data = t.getData();
- SchemaPath schemaPath = pathContext.getSchemaNode().getPath().getParent();
- if(data instanceof MapEntryNode) {
- data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).addChild((MapEntryNode) data).build();
- //schemaPath = pathContext.getSchemaNode().getPath();
+ SchemaPath schemaPath = pathContext.getSchemaNode().getPath();
+
+ // The utility method requires the path to be size of 2
+ boolean isRpc = false;
+ if(Iterables.size(schemaPath.getPathFromRoot()) > 1) {
+ isRpc = SchemaContextUtil.getRpcDataSchema(t.getInstanceIdentifierContext().getSchemaContext(), schemaPath) != null;
+ }
+
+ boolean isDataRoot = false;
+ if (SchemaPath.ROOT.equals(schemaPath)) {
+ isDataRoot = true;
+ // The rpc definitions required the schema path to point to the output container, not the parent (rpc itself)
+ } else {
+ if(!isRpc) {
+ schemaPath = schemaPath.getParent();
+ }
}
- NormalizedNodeStreamWriter jsonWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,pathContext.getSchemaContext(),schemaPath);
- NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(jsonWriter);
+ final NormalizedNodeStreamWriter jsonWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,
+ pathContext.getSchemaContext(), schemaPath);
+ final NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(jsonWriter);
+ if (isDataRoot) {
+ writeRootElement(xmlWriter, nnWriter, (ContainerNode) data, SchemaContext.NAME);
+ } else if(isRpc) {
+ writeRootElement(xmlWriter, nnWriter, (ContainerNode) data, schemaPath.getLastComponent());
+ } else {
+ if (data instanceof MapEntryNode) {
+ // Restconf allows returning one list item. We need to wrap it
+ // in map node in order to serialize it properly
+ data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).addChild((MapEntryNode) data).build();
+ }
+ nnWriter.write(data);
+ nnWriter.flush();
+ }
+ }
- nnWriter.write(data);
- nnWriter.flush();
+ private void writeRootElement(final XMLStreamWriter xmlWriter, final NormalizedNodeWriter nnWriter, final ContainerNode data, final QName name)
+ throws IOException {
+ try {
+ xmlWriter.writeStartElement(name.getNamespace().toString(), name.getLocalName());
+ for (final DataContainerChild<? extends PathArgument, ?> child : data.getValue()) {
+ nnWriter.write(child);
+ }
+ nnWriter.flush();
+ xmlWriter.writeEndElement();
+ xmlWriter.flush();
+ } catch (final XMLStreamException e) {
+ Throwables.propagate(e);
+ }
}
}