BUG 388: corrected media type in /operations resource 35/5035/3
authorMartin Sunal <msunal@cisco.com>
Thu, 30 Jan 2014 15:50:05 +0000 (16:50 +0100)
committerMartin Sunal <msunal@cisco.com>
Fri, 31 Jan 2014 14:28:19 +0000 (15:28 +0100)
There were added these media types for /operations resource:
application/yang.operation+json
application/yang.operation+xml
Corrected handling of requests which have empty body and Content-Type has some value or is missing

Change-Id: I148c22c4c6c28d0d13f2b717fe629b42d5c73f70
Signed-off-by: Martin Sunal <msunal@cisco.com>
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java

index 5300e2f21b28e15486ce19bdc9aac1b88dba0216..848f2c48ab10e2fb12ea4ca9c67481a5f65b6528 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.rest.api;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -23,30 +24,25 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 /**
  *   The URI hierarchy for the RESTCONF resources consists of an entry
 
 /**
  *   The URI hierarchy for the RESTCONF resources consists of an entry
- *   point container, 3 top-level resources, and 1 field.  Refer to
- *  Section 5 for details on each URI.
- *    <ul>
+ *   point container, 4 top-level resources, and 1 field.
+ *   <ul>
  *    <li><b>/restconf</b> - {@link #getRoot()}
  *    <li><b>/restconf</b> - {@link #getRoot()}
- *     <ul><li><b>/config</b> 
- *         <li><b>/operational</b> - {@link #readAllData()} - Added in Draft02
- *         <li><b>/datastore</b> - {@link #readAllData()}
- *         <ul>
- *            <li>/(top-level-data-nodes) (config=true or false)
- *         </ul>
- *         <li>/modules
- *          <ul><li>/module
- *              <li>/name
- *              <li>/revision
- *              <li>/namespace
- *              <li>/feature
- *             <li>/deviation
- *          </ul>
- *          <li>/operations
- *          <ul>
- *             <li>/(custom protocol operations)
- *          </ul>
- *         <li>/version (field)
+ *     <ul>
+ *      <li><b>/config</b> - {@link #readConfigurationData(String)} 
+ *                              {@link #updateConfigurationData(String, CompositeNode)}
+ *                              {@link #createConfigurationData(CompositeNode)}
+ *                              {@link #createConfigurationData(String, CompositeNode)}
+ *                              {@link #deleteConfigurationData(String)}
+ *      <li><b>/operational</b> - {@link #readOperationalData(String)} 
+ *      <li>/modules - {@link #getModules()}
+ *       <ul>
+ *        <li>/module
+ *       </ul>
+ *      <li><b>/operations</b> - {@link #invokeRpc(String, CompositeNode)}
+ *                               {@link #invokeRpc(String, CompositeNode)}
+ *      <li>/version (field)
  *     </ul>
  *     </ul>
+ *   </ul>
  */
 @Path("/")
 public interface RestconfService {
  */
 @Path("/")
 public interface RestconfService {
@@ -64,17 +60,20 @@ public interface RestconfService {
 
     @POST
     @Path("/operations/{identifier}")
 
     @POST
     @Path("/operations/{identifier}")
-    @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, 
+    @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
+               Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, 
+    @Consumes({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
+               Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
     public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
     
     @POST
     @Path("/operations/{identifier}")
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
     public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
     
     @POST
     @Path("/operations/{identifier}")
-    @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, 
+    @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
+               Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public StructuredData invokeRpc(@PathParam("identifier") String identifier);
+    public StructuredData invokeRpc(@PathParam("identifier") String identifier, @DefaultValue("") String noPayload);
     
     @GET
     @Path("/config/{identifier:.+}")
     
     @GET
     @Path("/config/{identifier:.+}")
index 06576abeec13f69263dde2edabcaa961187b0cb0..0d73485c80b3fcbceaddf7235d93737cad9fa40c 100644 (file)
@@ -25,7 +25,8 @@ import org.opendaylight.controller.sal.rest.api.RestconfService;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 @Provider
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 @Provider
-@Consumes({ Draft02.MediaTypes.DATA + RestconfService.JSON, MediaType.APPLICATION_JSON })
+@Consumes({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON,
+        MediaType.APPLICATION_JSON })
 public enum JsonToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
     INSTANCE;
 
 public enum JsonToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
     INSTANCE;
 
index 60850d3be1152d2ded67939805295e251a3f46a3..22e08d97f476679e5103779ccb6d6cec3a4d04fa 100644 (file)
@@ -31,7 +31,8 @@ import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import com.google.gson.stream.JsonWriter;
 
 @Provider
 import com.google.gson.stream.JsonWriter;
 
 @Provider
-@Produces({ Draft02.MediaTypes.DATA + RestconfService.JSON, MediaType.APPLICATION_JSON })
+@Produces({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON,
+        MediaType.APPLICATION_JSON })
 public enum StructuredDataToJsonProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
 
 public enum StructuredDataToJsonProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
 
index b0ebe7850114da94a70502a1efee54328cb82100..b6d8c953a9219a6c9b7b59cb0128c9b8b2ee98ae 100644 (file)
@@ -37,7 +37,8 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
 @Provider
 import org.w3c.dom.Document;
 
 @Provider
-@Produces({ Draft02.MediaTypes.DATA + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+@Produces({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML,
+        MediaType.APPLICATION_XML, MediaType.TEXT_XML })
 public enum StructuredDataToXmlProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
 
 public enum StructuredDataToXmlProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
 
index 875c6fffcf9ccf08ee7e120b51099580c33487c8..13d617031ad5717367ee50778c692ccfbda3fb16 100644 (file)
@@ -27,7 +27,8 @@ import org.opendaylight.controller.sal.restconf.impl.ResponseException;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 @Provider
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 @Provider
-@Consumes({ Draft02.MediaTypes.DATA + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+@Consumes({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML,
+        MediaType.APPLICATION_XML, MediaType.TEXT_XML })
 public enum XmlToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
     INSTANCE;
 
 public enum XmlToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
     INSTANCE;
 
index 59d058600a44894527a91af426157b9d53f9b1d6..cbfc3edf2cbf10ba164820aba15aa82749f0dbdd 100644 (file)
@@ -70,7 +70,10 @@ class RestconfImpl implements RestconfService {
         return callRpc(identifier.rpcDefinition, payload)
     }
 
         return callRpc(identifier.rpcDefinition, payload)
     }
 
-    override invokeRpc(String identifier) {
+    override invokeRpc(String identifier, String noPayload) {
+        if (!noPayload.nullOrEmpty) {
+            throw new ResponseException(UNSUPPORTED_MEDIA_TYPE, "Content-Type contains unsupported Media Type.");
+        }
         return callRpc(identifier.rpcDefinition, null)
     }
 
         return callRpc(identifier.rpcDefinition, null)
     }
 
index 2a8ab7a344964b8a99e952a6d9336d1145b35e30..e1d7e6a62447d3b1145c4bb672267ec77e4fc762 100644 (file)
@@ -72,9 +72,9 @@ public class MediaTypesTest extends JerseyTest {
       String uriPath = "ietf-interfaces:interfaces";
       String uri = createUri(uriPrefix, uriPath);
       when(restconfService.invokeRpc(eq(uriPath), any(CompositeNode.class))).thenReturn(null);
       String uriPath = "ietf-interfaces:interfaces";
       String uri = createUri(uriPrefix, uriPath);
       when(restconfService.invokeRpc(eq(uriPath), any(CompositeNode.class))).thenReturn(null);
-      post(uri, Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+JSON, jsonData);
+      post(uri, Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+JSON, jsonData);
       verify(restconfService, times(1)).invokeRpc(eq(uriPath), any(CompositeNode.class));
       verify(restconfService, times(1)).invokeRpc(eq(uriPath), any(CompositeNode.class));
-      post(uri, Draft02.MediaTypes.DATA+XML, Draft02.MediaTypes.DATA+XML, xmlData);
+      post(uri, Draft02.MediaTypes.OPERATION+XML, Draft02.MediaTypes.OPERATION+XML, xmlData);
       verify(restconfService, times(2)).invokeRpc(eq(uriPath), any(CompositeNode.class));
       post(uri, MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, jsonData);
       verify(restconfService, times(3)).invokeRpc(eq(uriPath), any(CompositeNode.class));
       verify(restconfService, times(2)).invokeRpc(eq(uriPath), any(CompositeNode.class));
       post(uri, MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, jsonData);
       verify(restconfService, times(3)).invokeRpc(eq(uriPath), any(CompositeNode.class));