Skip to content

Commit

Permalink
Added UriInfo#getMatchedResourceTemplate method (#1236)
Browse files Browse the repository at this point in the history
* Added UriInfo#getMatchedResourceTemplate method

Signed-off-by: jansupol <jan.supol@oracle.com>

* Reflected review comments
Added TCK tests

Signed-off-by: jansupol <jan.supol@oracle.com>

* Renamed the client class

Signed-off-by: jansupol <jan.supol@oracle.com>

* Added @path to Sub-resource method

Signed-off-by: jansupol <jan.supol@oracle.com>

---------

Signed-off-by: jansupol <jan.supol@oracle.com>
  • Loading branch information
jansupol committed Mar 28, 2024
1 parent d0c5fea commit 7c34889
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 1 deletion.
69 changes: 68 additions & 1 deletion 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
Expand All @@ -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
Expand Down Expand Up @@ -230,6 +232,71 @@ public interface UriInfo {
*/
public List<String> getMatchedURIs();

/**
* <p>
* Get a URI template that includes all {@link Path Paths} (including {@link ApplicationPath})
* matched by the current request's URI.
* </p>
* <p>
* 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:
* </p>
*
* <pre>
* &#064;Path("foo")
* public class FooResource {
* &#064;GET
* &#064;Path("{foo:[f-z][a-z]*}")
* public String getFoo() {...}
*
* &#064;Path("{bar:[b-e][a-z]*}")
* public BarResource getBarResource() {...}
* }
*
* public class BarResource {
* &#064;GET
* &#064;Path("{id}{id:[0-9]}")
* public String getBar() {...}
* }
* </pre>
*
* <p>
* The values returned by this method based on request uri and where the method is called from are:
* </p>
*
* <table border="1">
* <caption>Matched URIs from requests</caption>
* <tr>
* <th>Request</th>
* <th>Called from</th>
* <th>Value(s)</th>
* </tr>
* <tr>
* <td>GET /foo</td>
* <td>FooResource.getFoo</td>
* <td>/foo/{foo:[f-z][a-z]*}</td>
* </tr>
* <tr>
* <td>GET /foo/bar</td>
* <td>FooResource.getBarResource</td>
* <td>/foo/{bar:[b-e][a-z]*}</td>
* </tr>
* <tr>
* <td>GET /foo/bar/id0</td>
* <td>BarResource.getBar</td>
* <td>/foo/{bar:[b-e][a-z]*}/{id}{id:[0-9]}</td>
* </tr>
* </table>
*
* 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.
*
Expand Down
@@ -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<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<Class<?>>();
resources.add(UriInfoTestResource.class);
return resources;
}
}
@@ -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();
}
}
@@ -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();
}
}

0 comments on commit 7c34889

Please sign in to comment.