From 7c34889ea136dde6d6cac2b73df11ad73c96eb87 Mon Sep 17 00:00:00 2001 From: jansupol <15908245+jansupol@users.noreply.github.com> Date: Thu, 28 Mar 2024 14:52:25 +0100 Subject: [PATCH] Added UriInfo#getMatchedResourceTemplate method (#1236) * Added UriInfo#getMatchedResourceTemplate method Signed-off-by: jansupol * Reflected review comments Added TCK tests Signed-off-by: jansupol * Renamed the client class Signed-off-by: jansupol * Added @Path to Sub-resource method Signed-off-by: jansupol --------- Signed-off-by: jansupol --- .../main/java/jakarta/ws/rs/core/UriInfo.java | 69 +++++++++- .../ee/rs/core/uriinfo/TSAppConfig.java | 33 +++++ .../ee/rs/core/uriinfo/UriInfo40ClientIT.java | 125 ++++++++++++++++++ .../rs/core/uriinfo/UriInfoTestResource.java | 64 +++++++++ 4 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/TSAppConfig.java create mode 100644 jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/UriInfo40ClientIT.java create mode 100644 jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/UriInfoTestResource.java diff --git a/jaxrs-api/src/main/java/jakarta/ws/rs/core/UriInfo.java b/jaxrs-api/src/main/java/jakarta/ws/rs/core/UriInfo.java index 26a0a9f3a..2fad2945e 100644 --- a/jaxrs-api/src/main/java/jakarta/ws/rs/core/UriInfo.java +++ b/jaxrs-api/src/main/java/jakarta/ws/rs/core/UriInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -18,6 +18,8 @@ import java.net.URI; import java.util.List; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.ApplicationPath; /** * An injectable interface that provides access to application and request URI information. Relative URIs are relative @@ -230,6 +232,71 @@ public interface UriInfo { */ public List getMatchedURIs(); + /** + *

+ * Get a URI template that includes all {@link Path Paths} (including {@link ApplicationPath}) + * matched by the current request's URI. + *

+ *

+ * Each {@link Path} value used to match a resource class, a sub-resource method or a sub-resource locator is concatenated + * into a single {@code String} value. The template does not include query parameters but does include matrix parameters + * if present in the request URI. The concatenation is ordered in the request URI matching order, with the + * {@link ApplicationPath} value first and current resource URI last. E.g. given the following resource classes: + *

+ * + *
+     * @Path("foo")
+     * public class FooResource {
+     *  @GET
+     *  @Path("{foo:[f-z][a-z]*}")
+     *  public String getFoo() {...}
+     *
+     *  @Path("{bar:[b-e][a-z]*}")
+     *  public BarResource getBarResource() {...}
+     * }
+     *
+     * public class BarResource {
+     *  @GET
+     *  @Path("{id}{id:[0-9]}")
+     *  public String getBar() {...}
+     * }
+     * 
+ * + *

+ * The values returned by this method based on request uri and where the method is called from are: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Matched URIs from requests
RequestCalled fromValue(s)
GET /fooFooResource.getFoo/foo/{foo:[f-z][a-z]*}
GET /foo/barFooResource.getBarResource/foo/{bar:[b-e][a-z]*}
GET /foo/bar/id0BarResource.getBar/foo/{bar:[b-e][a-z]*}/{id}{id:[0-9]}
+ * + * In case the method is invoked prior to the request matching (e.g. from a pre-matching filter), the method returns an + * empty string. + * + * @return A concatenated string of {@link Path} templates. + */ + public String getMatchedResourceTemplate(); + /** * Get a read-only list of URIs for matched resources. * diff --git a/jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/TSAppConfig.java b/jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/TSAppConfig.java new file mode 100644 index 000000000..afcfddae8 --- /dev/null +++ b/jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/TSAppConfig.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package ee.jakarta.tck.ws.rs.jaxrs40.ee.rs.core.uriinfo; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +import java.util.HashSet; +import java.util.Set; + +@ApplicationPath("/app") +public class TSAppConfig extends Application { + + public Set> getClasses() { + Set> resources = new HashSet>(); + resources.add(UriInfoTestResource.class); + return resources; + } +} diff --git a/jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/UriInfo40ClientIT.java b/jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/UriInfo40ClientIT.java new file mode 100644 index 000000000..f6c20ad4d --- /dev/null +++ b/jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/UriInfo40ClientIT.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package ee.jakarta.tck.ws.rs.jaxrs40.ee.rs.core.uriinfo; + +import ee.jakarta.tck.ws.rs.common.JAXRSCommonClient; +import ee.jakarta.tck.ws.rs.lib.util.TestUtil; +import jakarta.ws.rs.core.UriInfo; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit5.ArquillianExtension; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.io.IOException; + +/* + * @class.setup_props: webServerHost; + * webServerPort; + */ +@ExtendWith(ArquillianExtension.class) +public class UriInfo40ClientIT extends JAXRSCommonClient { + protected static final String ROOT = "jaxrs40_ee_core_uriinfo_web"; + + protected static final String RESOURCE = "app/resource"; + + public UriInfo40ClientIT() { + setup(); + setContextRoot("/" + ROOT + "/" + RESOURCE); + } + + + @BeforeEach + void logStartTest(TestInfo testInfo) { + TestUtil.logMsg("STARTING TEST : " + testInfo.getDisplayName()); + } + + @AfterEach + void logFinishTest(TestInfo testInfo) { + TestUtil.logMsg("FINISHED TEST : " + testInfo.getDisplayName()); + } + + @Deployment(testable = false) + public static WebArchive createDeployment() throws IOException{ + WebArchive archive = ShrinkWrap.create(WebArchive.class, "jaxrs40_ee_core_uriinfo_web.war"); + archive.addClasses(TSAppConfig.class, UriInfoTestResource.class); + return archive; + } + + /* Run test */ + + /** + * @testName: getMatchedResourceTemplateOneTest + * + * @assertion_ids: JAXRS:JAVADOC:97; + * + * @test_Strategy: Check the template containing {@link UriInfoTestResource#ONE_POST} + */ + @Test + public void getMatchedResourceTemplateOneTest() throws Fault { + setProperty(Property.REQUEST, buildRequest(Request.POST, "one/azazaz00")); + setProperty(Property.SEARCH_STRING, "/app/resource/one/" + UriInfoTestResource.ONE_POST); + invoke(); + } + + /** + * @testName: getMatchedResourceTemplateTwoGetTest + * + * @assertion_ids: JAXRS:JAVADOC:97; + * + * @test_Strategy: Check the template containing {@link UriInfoTestResource#TWO_GET} + */ + @Test + public void getMatchedResourceTemplateTwoGetTest() throws Fault { + setProperty(Property.REQUEST, buildRequest(Request.GET, "two/P/abc/MyNumber")); + setProperty(Property.SEARCH_STRING, "/app/resource/two/" + UriInfoTestResource.TWO_GET); + invoke(); + } + + /** + * @testName: getMatchedResourceTemplateTwoPostTest + * + * @assertion_ids: JAXRS:JAVADOC:97; + * + * @test_Strategy: Check the template containing {@link UriInfoTestResource#TWO_POST} + */ + @Test + public void getMatchedResourceTemplateTwoPostTest() throws Fault { + setProperty(Property.REQUEST, buildRequest(Request.POST, "two/P/abc/MyNumber")); + setProperty(Property.SEARCH_STRING, "/app/resource/two/" + UriInfoTestResource.TWO_POST); + invoke(); + } + + /** + * @testName: getMatchedResourceTemplateSubTest + * + * @assertion_ids: JAXRS:JAVADOC:97; + * + * @test_Strategy: Check the template including subresource containing {@link UriInfoTestResource#THREE_SUB} + */ + @Test + public void getMatchedResourceTemplateSubTest() throws Fault { + setProperty(Property.REQUEST, buildRequest(Request.PUT, "three/a/z")); + setProperty(Property.SEARCH_STRING, + "/app/resource/three/" + UriInfoTestResource.THREE_SUB + "/" + UriInfoTestResource.THREE_SUB); + invoke(); + } +} diff --git a/jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/UriInfoTestResource.java b/jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/UriInfoTestResource.java new file mode 100644 index 000000000..f64848285 --- /dev/null +++ b/jaxrs-tck/src/main/java/ee/jakarta/tck/ws/rs/jaxrs40/ee/rs/core/uriinfo/UriInfoTestResource.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package ee.jakarta.tck.ws.rs.jaxrs40.ee.rs.core.uriinfo; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; + +@Path("/resource") +public class UriInfoTestResource { + public static final String ONE_POST = "{name:[a-zA-Z][a-zA-Z_0-9]*}"; + public static final String TWO_GET = "{Prefix}{p:/?}{id: ((\\d+)?)}/abc{p2:/?}{number: (([A-Za-z0-9]*)?)}"; + public static final String TWO_POST = "{Prefix}{p:/?}{id: ((\\d+)?)}/abc/{yeah}"; + public static final String THREE_SUB = "{x:[a-z]}"; + + public static class SubGet { + @PUT + @Path(THREE_SUB) + public String get(@Context UriInfo uriInfo) { + return uriInfo.getMatchedResourceTemplate(); + } + } + + @POST + @Path("one/" + ONE_POST) + public Response post(@Context UriInfo info) { + return Response.ok(info.getMatchedResourceTemplate()).build(); + } + + @GET + @Path("two/" + TWO_GET) + public Response get(@Context UriInfo info) { + return Response.ok(info.getMatchedResourceTemplate()).build(); + } + + @POST + @Path("two/" + TWO_POST) + public Response postTwo(@Context UriInfo info) { + return Response.ok(info.getMatchedResourceTemplate()).build(); + } + + @Path("three/" + THREE_SUB) + public SubGet doAnything4() { + return new SubGet(); + } +}