Implement RESTCONF Extensibility (discovery) 19/89419/16
authorwsx25289 <10200860@zte.com.cn>
Tue, 28 Apr 2020 07:58:36 +0000 (03:58 -0400)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 18 Dec 2020 10:45:52 +0000 (11:45 +0100)
Added Root Resource Discovery mechanism according to RFC8040,
serving host-meta documents.

The copyright headers are the best we could back-engineer, as it
seems original code used copy&paste templating.

JIRA: NETCONF-499
Change-Id: I414ebda7e34db7cd468fb0e488bcac457d7cf7ff
Signed-off-by: Wsx25289 <10200860@zte.com.cn>
Signed-off-by: Iaroslav <iaroslav.kholiavko@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/Rfc8040.java
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/RootFoundApplication.java [new file with mode: 0644]
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/api/RootResourceDiscoveryService.java [new file with mode: 0644]
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/services/wrapper/RootResourceDiscoveryServiceImpl.java [new file with mode: 0644]
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/web/WebInitializer.java
restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/services/wrapper/RRDSImplTest.java [new file with mode: 0644]

index 99e52256ea68265162c0de6e45d4bc3efbf25a43..7618eb2be8e278f5cd6124969abe824ad731dcd3 100644 (file)
@@ -43,6 +43,11 @@ public final class Rfc8040 {
             throw new UnsupportedOperationException("Util class");
         }
 
+        /**
+         * See: <a href="https://tools.ietf.org/html/rfc6415">rfc6415</a>.
+         */
+        public static final String XRD = "application/xrd";
+
         public static final String DATA = "application/yang-data";
         public static final String YANG_PATCH = "application/yang.patch";
         public static final String YANG_PATCH_STATUS = "application/yang.patch-status";
diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/RootFoundApplication.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/RootFoundApplication.java
new file mode 100644 (file)
index 0000000..d0cbef0
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020 ZTE Corp. 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.restconf.nb.rfc8040;
+
+import java.util.Set;
+import javax.ws.rs.core.Application;
+import org.opendaylight.restconf.nb.rfc8040.jersey.providers.errors.RestconfDocumentedExceptionMapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RootResourceDiscoveryService;
+import org.opendaylight.restconf.nb.rfc8040.services.wrapper.RootResourceDiscoveryServiceImpl;
+
+public class RootFoundApplication extends Application {
+    private final RootResourceDiscoveryService rrds = new RootResourceDiscoveryServiceImpl();
+
+    @Override
+    public Set<Class<?>> getClasses() {
+        return Set.of(RestconfDocumentedExceptionMapper.class);
+    }
+
+    @Override
+    public Set<Object> getSingletons() {
+        return Set.of(rrds);
+    }
+}
diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/api/RootResourceDiscoveryService.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/api/RootResourceDiscoveryService.java
new file mode 100644 (file)
index 0000000..f670b8b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 ZTE Corp. 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.restconf.nb.rfc8040.rests.services.api;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import org.opendaylight.restconf.nb.rfc8040.Rfc8040;
+import org.opendaylight.restconf.nb.rfc8040.utils.RestconfConstants;
+
+/**
+ * Controller for determining the {@code Root Resource} of the RESTCONF API. This interface serves up a
+ * {@code host-meta} document as defined in
+ * <a href="https://tools.ietf.org/html/rfc8040#section-3">RFC6415 section 3</a>.
+ */
+// FIXME: this really should be the endpoint's job to aggregate these. Once JAX-RS (or any other wiring) can provide it,
+//        integrate with that framework, so we co-exist with others.
+public interface RootResourceDiscoveryService {
+    /**
+     * Root Resource Discovery. See: https://tools.ietf.org/html/rfc8040#section-3.1
+     */
+    @GET
+    @Path("/host-meta")
+    @Produces({Rfc8040.MediaTypes.XRD + RestconfConstants.XML})
+    Response readXrdData();
+
+    /**
+     * Root Resource Discovery as a <a href="https://tools.ietf.org/html/rfc6415#appendix-A">JRD</a>.
+     */
+    @GET
+    @Path("/host-meta.json")
+    @Produces({Rfc8040.MediaTypes.XRD + RestconfConstants.JSON})
+    Response readJsonData();
+}
diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/services/wrapper/RootResourceDiscoveryServiceImpl.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/services/wrapper/RootResourceDiscoveryServiceImpl.java
new file mode 100644 (file)
index 0000000..3f982f6
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020 ZTE Corp. 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.restconf.nb.rfc8040.services.wrapper;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RootResourceDiscoveryService;
+import org.opendaylight.restconf.nb.rfc8040.utils.RestconfConstants;
+
+@Path("/")
+public final class RootResourceDiscoveryServiceImpl implements RootResourceDiscoveryService {
+    private final Response xrdData = Response.status(Status.OK)
+        .entity("<?xml version='1.0' encoding='UTF-8'?>\n"
+            + "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>\n"
+            + "     <Link rel='restconf' href='/" + RestconfConstants.BASE_URI_PATTERN + "'/>\n"
+            + "</XRD>")
+        .build();
+    private final Response jsonData = Response.status(Status.OK)
+        .entity("{\n"
+            + " \"links\" :\n"
+            + " {\n"
+            + "     \"rel\" : \"restconf\",\n"
+            + "     \"href\" : \"/" + RestconfConstants.BASE_URI_PATTERN + "/\"\n"
+            + " }\n"
+            + "}")
+        .build();
+
+    @Override
+    public Response readXrdData() {
+        return xrdData;
+    }
+
+    @Override
+    public Response readJsonData() {
+        return jsonData;
+    }
+}
+
index c8cfb1c613aa27a1d4d2eef670a4c7f2f784411d..ca6aa983f9ef5bc993f1f685a9e4ac11e5bee50a 100644 (file)
@@ -25,6 +25,7 @@ import org.opendaylight.aaa.web.WebServer;
 import org.opendaylight.aaa.web.servlet.ServletSupport;
 import org.opendaylight.restconf.nb.rfc8040.RestconfApplication;
 import org.opendaylight.restconf.nb.rfc8040.RestconfNotifApplication;
+import org.opendaylight.restconf.nb.rfc8040.RootFoundApplication;
 import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfStreamsConstants;
 import org.opendaylight.restconf.nb.rfc8040.streams.websockets.WebSocketInitializer;
 import org.opendaylight.restconf.nb.rfc8040.utils.RestconfConstants;
@@ -44,15 +45,22 @@ public class WebInitializer {
             @Reference ServletSupport servletSupport, RestconfApplication webApp,RestconfNotifApplication webAppNotif,
             @Reference CustomFilterAdapterConfiguration customFilterAdapterConfig,
             WebSocketInitializer webSocketServlet) throws ServletException {
-        WebContextBuilder webContextBuilder = WebContext.builder().contextPath(RestconfConstants.BASE_URI_PATTERN)
+        WebContextBuilder webContextBuilder = WebContext.builder().contextPath("/")
                 .supportsSessions(false)
                 .addServlet(ServletDetails.builder().servlet(servletSupport.createHttpServletBuilder(webApp).build())
-                        .addUrlPattern("/*").build())
+                        .addUrlPattern(RestconfConstants.BASE_URI_PATTERN + "/*").build())
                 .addServlet(ServletDetails.builder().servlet(servletSupport.createHttpServletBuilder(webAppNotif)
-                        .build()).asyncSupported(true).addUrlPattern("/notif/*").name("notificationServlet").build())
+                        .build()).asyncSupported(true).addUrlPattern(RestconfConstants.BASE_URI_PATTERN + "/notif/*")
+                        .name("notificationServlet").build())
                 .addServlet(ServletDetails.builder().servlet(webSocketServlet).addAllUrlPatterns(Lists.newArrayList(
-                        RestconfStreamsConstants.DATA_CHANGE_EVENT_STREAM_PATTERN,
-                        RestconfStreamsConstants.YANG_NOTIFICATION_STREAM_PATTERN)).build())
+                        RestconfConstants.BASE_URI_PATTERN + RestconfStreamsConstants.DATA_CHANGE_EVENT_STREAM_PATTERN,
+                        RestconfConstants.BASE_URI_PATTERN + RestconfStreamsConstants.YANG_NOTIFICATION_STREAM_PATTERN))
+                        .build())
+
+                .addServlet(ServletDetails.builder().servlet(servletSupport.createHttpServletBuilder(
+                            new RootFoundApplication()).build())
+                        .addUrlPattern(".well-known/*").name("Rootfound").build())
+
                 // Allows user to add javax.servlet.Filter(s) in front of REST services
                 .addFilter(FilterDetails.builder().filter(new CustomFilterAdapter(customFilterAdapterConfig))
                     .addUrlPattern("/*").asyncSupported(true).build());
diff --git a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/services/wrapper/RRDSImplTest.java b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/services/wrapper/RRDSImplTest.java
new file mode 100644 (file)
index 0000000..d3679b3
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.nb.rfc8040.services.wrapper;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class RRDSImplTest {
+    @Test
+    public void testHostMeta() {
+        assertEquals("<?xml version='1.0' encoding='UTF-8'?>\n"
+            + "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>\n"
+            + "     <Link rel='restconf' href='/rests'/>\n"
+            + "</XRD>", new RootResourceDiscoveryServiceImpl().readXrdData().getEntity());
+    }
+}