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";
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
+
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;
@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());
--- /dev/null
+/*
+ * 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());
+ }
+}