Skip to content

Commit

Permalink
Separate tests using jmockit from jersey core (eclipse-ee4j#4125)
Browse files Browse the repository at this point in the history
Signed-off-by: Jan Supol <jan.supol@oracle.com>
  • Loading branch information
jansupol committed May 16, 2019
1 parent 8c60fd2 commit 10470c0
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ private int compare(List<MediaType> mediaTypeList1, List<MediaType> mediaTypeLis
}
}

/* package */ Set<String> getHttpMethods() {
return consumesProducesAcceptors.keySet();
}

/**
* Represents a 1-1-1 relation between input and output media type and an methodAcceptorPair.
* <p>E.g. for a single resource method
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2019 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 @@ -16,14 +16,18 @@

package org.glassfish.jersey.server.internal.routing;

import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.regex.MatchResult;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.glassfish.jersey.message.internal.TracingLogger;
import org.glassfish.jersey.server.internal.ServerTraceEvent;
import org.glassfish.jersey.server.internal.process.RequestProcessingContext;
import org.glassfish.jersey.uri.PathPattern;
import org.glassfish.jersey.uri.UriTemplate;

/**
* Matches the un-matched right-hand request path to the configured collection of path pattern matching routes.
Expand All @@ -34,6 +38,7 @@
final class PathMatchingRouter implements Router {

private final List<Route> acceptedRoutes;
private static final RouteComparator ROUTE_COMPARATOR = new RouteComparator();

/**
* Constructs route methodAcceptorPair that uses {@link PathPattern} instances for
Expand All @@ -56,15 +61,26 @@ public Router.Continuation apply(final RequestProcessingContext context) {
tracingLogger.log(ServerTraceEvent.MATCH_PATH_FIND, path);

Router.Continuation result = null;
final Iterator<Route> iterator = acceptedRoutes.iterator();
//need sort if regexes in the @Path, keep original sort if no regexes
// final boolean needSort = acceptedRoutes
// .stream()
// .map(a -> a.routingPattern().getTemplate().getNumberOfExplicitRegexes())
// .reduce(0, Integer::sum) > 0;
final boolean needSort = true;

final Stream<ComparableRoute> comparableRoutes = acceptedRoutes
.stream()
.map(a -> new ComparableRoute(a, context, path, needSort));
final Stream<ComparableRoute> sortedRoutes = needSort ? comparableRoutes.sorted(ROUTE_COMPARATOR) : comparableRoutes;
final Iterator<ComparableRoute> iterator = sortedRoutes.iterator();

while (iterator.hasNext()) {
final Route acceptedRoute = iterator.next();
final PathPattern routePattern = acceptedRoute.routingPattern();
final MatchResult m = routePattern.match(path);
if (m != null) {
final ComparableRoute acceptedRoute = iterator.next();
final PathPattern routePattern = acceptedRoute.route.routingPattern();
if (acceptedRoute.matchResult != null) {
// Push match result information and rest of path to match
rc.pushMatchResult(m);
result = Router.Continuation.of(context, acceptedRoute.next());
rc.pushMatchResult(acceptedRoute.matchResult);
result = Router.Continuation.of(context, acceptedRoute.route.next());

//tracing
tracingLogger.log(ServerTraceEvent.MATCH_PATH_SELECTED, routePattern.getRegex());
Expand All @@ -76,7 +92,7 @@ public Router.Continuation apply(final RequestProcessingContext context) {

if (tracingLogger.isLogEnabled(ServerTraceEvent.MATCH_PATH_SKIPPED)) {
while (iterator.hasNext()) {
tracingLogger.log(ServerTraceEvent.MATCH_PATH_SKIPPED, iterator.next().routingPattern().getRegex());
tracingLogger.log(ServerTraceEvent.MATCH_PATH_SKIPPED, iterator.next().route.routingPattern().getRegex());
}
}

Expand All @@ -87,4 +103,81 @@ public Router.Continuation apply(final RequestProcessingContext context) {

return result;
}

private static class ComparableRoute {
private final Route route;
private final MatchResult matchResult;
private final boolean hasMethodSelectingRouter;
private final boolean hasRequestedMethodDesignator;

/**
* Route decorator for possible sort
* @param route The original {@link Route}
* @param context The context containing request method
* @param path The path to be matched
* @param needDesignator Designator is needed only when sort is needed, i.e. when regexes in @Path
*/
private ComparableRoute(Route route, RequestProcessingContext context, String path, boolean needDesignator) {
this.route = route;
this.matchResult = route.routingPattern().match(path);
final List<MethodSelectingRouter> routers = !needDesignator || matchResult == null ? null : route
.next()
.stream()
.filter(MethodSelectingRouter.class::isInstance)
.map(MethodSelectingRouter.class::cast)
.collect(Collectors.toList());
this.hasMethodSelectingRouter = !(routers == null || routers.isEmpty());
this.hasRequestedMethodDesignator = !hasMethodSelectingRouter
? false : routers.stream().anyMatch(a -> a.getHttpMethods().contains(context.request().getMethod()));
}
}

/**
* There {@link Route routes} can be multiple routes each accessible by a request, in case
* different regular expressions gets matched by the request Uri. In that case, the routes are
* sorted so that the ones that do not have a proper method designator are at the bottom of the list.
* This step corresponds to Step 3 in Request Matching Algorithm. Also, the sort respects sorting by
* the regular expressions (UriTemplates) as mandated by the Algorithm.
*/
private static class RouteComparator implements Comparator<ComparableRoute> {

@Override
public int compare(ComparableRoute r1, ComparableRoute r2) {
if (r2.matchResult == null) {
return -1;
}
if (r1.matchResult == null) {
return 1;
}
if (!r2.hasMethodSelectingRouter && r1.hasMethodSelectingRouter) {
return -1;
}
if (r2.hasMethodSelectingRouter && !r1.hasMethodSelectingRouter) {
return 1;
}
if (!r2.hasRequestedMethodDesignator && r1.hasRequestedMethodDesignator) {
return -1;
}
if (r2.hasRequestedMethodDesignator && !r1.hasRequestedMethodDesignator) {
return 1;
}
return compareTemplates(r1.route.routingPattern().getTemplate(), r2.route.routingPattern().getTemplate());
}

private int compareTemplates(UriTemplate t1, UriTemplate t2) {
if (t1.getNumberOfExplicitCharacters() > t2.getNumberOfExplicitCharacters()) {
return -1;
}
if (t1.getNumberOfExplicitCharacters() < t2.getNumberOfExplicitCharacters()) {
return 1;
}
if (t1.getNumberOfExplicitRegexes() > t2.getNumberOfExplicitRegexes()) {
return -1;
}
if (t1.getNumberOfExplicitRegexes() < t2.getNumberOfExplicitRegexes()) {
return 1;
}
return t1.getNumberOfRegexGroups() - t2.getNumberOfRegexGroups() > 0 ? -1 : 1;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2013, 2019 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 org.glassfish.jersey.tests.e2e.server.routing;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

public class RegularExpressionsTest extends JerseyTest {
public static String GET_VALUE = "get value";
public static String POST_VALUE = "post value";


@Path("one")
public static class ResourceOne {
@POST
public String post(String entity) {
return entity;
}

@GET
@Path("x")
public Response get() {
return Response.ok(GET_VALUE).build();

}

@POST
@Path("{name:[a-zA-Z][a-zA-Z_0-9]*}")
public Response post() {
return Response.ok(POST_VALUE).build();

}

@Path("{x:[a-z]}")
public SubGet doAnything4() {
return new SubGet();
}
}

@Path("two")
public static class ResourceTwo {
@GET
@Path("{Prefix}{p:/?}{id: ((\\d+)?)}/abc{p2:/?}{number: (([A-Za-z0-9]*)?)}")
public Response get() {
return Response.ok(GET_VALUE).build();

}

@POST
@Path("{Prefix}{p:/?}{id: ((\\d+)?)}/abc/{yeah}")
public Response post() {
return Response.ok(POST_VALUE).build();

}
}

public static class SubGet {
@PUT
public String get() {
return "TEST";
}
}

@Override
protected Application configure() {
return new ResourceConfig(ResourceOne.class, ResourceTwo.class);
}

@Test
public void testPostOne() {
String entity = target("one").path("x").request()
.buildPost(Entity.entity("AA", MediaType.TEXT_PLAIN_TYPE)).invoke().readEntity(String.class);
assertThat(entity, is(POST_VALUE));
}

@Test
public void testGetOne() {
String entity = target("one").path("x").request().buildGet().invoke().readEntity(String.class);
assertThat(entity, is(GET_VALUE));
}

@Test
public void testPostTwo() {
String entity = target("two").path("P/abc/MyNumber").request()
.buildPost(Entity.entity("AA", MediaType.TEXT_PLAIN_TYPE)).invoke().readEntity(String.class);
assertThat(entity, is(POST_VALUE));
}

@Test
public void testGetTwo() {
String entity = target("two").path("P/abc/MyNumber").request().buildGet().invoke().readEntity(String.class);
assertThat(entity, is(GET_VALUE));
}
}

0 comments on commit 10470c0

Please # to comment.