All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.glassfish.jersey.server.internal.routing.UriRoutingContext Maven / Gradle / Ivy
Go to download
A bundle project producing JAX-RS RI bundles. The primary artifact is an "all-in-one" OSGi-fied JAX-RS RI bundle
(jaxrs-ri.jar).
Attached to that are two compressed JAX-RS RI archives. The first archive (jaxrs-ri.zip) consists of binary RI bits and
contains the API jar (under "api" directory), RI libraries (under "lib" directory) as well as all external
RI dependencies (under "ext" directory). The secondary archive (jaxrs-ri-src.zip) contains buildable JAX-RS RI source
bundle and contains the API jar (under "api" directory), RI sources (under "src" directory) as well as all external
RI dependencies (under "ext" directory). The second archive also contains "build.xml" ANT script that builds the RI
sources. To build the JAX-RS RI simply unzip the archive, cd to the created jaxrs-ri directory and invoke "ant" from
the command line.
/*
* Copyright (c) 2011, 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 org.glassfish.jersey.server.internal.routing;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.MatchResult;
import java.util.stream.Collectors;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.PathSegment;
import jakarta.ws.rs.core.UriBuilder;
import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap;
import org.glassfish.jersey.internal.util.collection.LazyValue;
import org.glassfish.jersey.internal.util.collection.Value;
import org.glassfish.jersey.internal.util.collection.Values;
import org.glassfish.jersey.message.internal.TracingLogger;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.internal.ServerTraceEvent;
import org.glassfish.jersey.server.internal.process.Endpoint;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.server.model.ResourceMethod;
import org.glassfish.jersey.server.model.ResourceMethodInvoker;
import org.glassfish.jersey.server.model.RuntimeResource;
import org.glassfish.jersey.uri.UriComponent;
import org.glassfish.jersey.uri.UriTemplate;
import org.glassfish.jersey.uri.internal.JerseyUriBuilder;
/**
* Default implementation of the routing context as well as URI information provider.
*
* @author Marek Potociar
*/
public class UriRoutingContext implements RoutingContext {
private final LinkedList matchResults = new LinkedList<>();
private final LinkedList matchedResources = new LinkedList<>();
private final LinkedList templates = new LinkedList<>();
private final MultivaluedHashMap encodedTemplateValues = new MultivaluedHashMap<>();
private final ImmutableMultivaluedMap encodedTemplateValuesView =
new ImmutableMultivaluedMap<>(encodedTemplateValues);
private final LinkedList paths = new LinkedList<>();
private final LinkedList matchedRuntimeResources = new LinkedList<>();
private final LinkedList matchedLocators = new LinkedList<>();
private final LinkedList locatorSubResources = new LinkedList<>();
private final LazyValue tracingLogger;
private volatile ResourceMethod matchedResourceMethod = null;
private volatile Throwable mappedThrowable = null;
private Endpoint endpoint;
private MultivaluedHashMap decodedTemplateValues;
private ImmutableMultivaluedMap decodedTemplateValuesView;
private ImmutableMultivaluedMap encodedQueryParamsView;
private ImmutableMultivaluedMap decodedQueryParamsView;
/**
* Injection constructor.
*
* @param requestContext request reference.
*/
public UriRoutingContext(final ContainerRequest requestContext) {
this.requestContext = requestContext;
// Tracing Logger is initialized after UriContext before pushMatchedResource
this.tracingLogger = Values.lazy((Value) () -> TracingLogger.getInstance(requestContext));
}
// RoutingContext
@Override
public void pushMatchResult(final MatchResult matchResult) {
matchResults.push(matchResult);
}
@Override
public void pushMatchedResource(final Object resource) {
tracingLogger.get().log(ServerTraceEvent.MATCH_RESOURCE, resource);
matchedResources.push(resource);
}
@Override
public Object peekMatchedResource() {
return matchedResources.peek();
}
@Override
public void pushMatchedLocator(final ResourceMethod resourceLocator) {
tracingLogger.get().log(ServerTraceEvent.MATCH_LOCATOR, resourceLocator.getInvocable().getHandlingMethod());
matchedLocators.push(resourceLocator);
}
@Override
public void pushLeftHandPath() {
final String rightHandPath = getFinalMatchingGroup();
final int rhpLength = (rightHandPath != null) ? rightHandPath.length() : 0;
final String encodedRequestPath = getPath(false);
final int length = encodedRequestPath.length() - rhpLength;
if (length <= 0) {
paths.addFirst("");
} else {
paths.addFirst(encodedRequestPath.substring(0, length));
}
}
@Override
public void pushTemplates(final UriTemplate resourceTemplate, final UriTemplate methodTemplate) {
final Iterator matchResultIterator = matchResults.iterator();
templates.push(resourceTemplate);
if (methodTemplate != null) {
templates.push(methodTemplate);
// fast-forward the match result iterator to second element in the stack
matchResultIterator.next();
}
pushMatchedTemplateValues(resourceTemplate, matchResultIterator.next());
if (methodTemplate != null) {
// use the match result from the top of the stack
pushMatchedTemplateValues(methodTemplate, matchResults.peek());
}
}
private void pushMatchedTemplateValues(final UriTemplate template, final MatchResult matchResult) {
int i = 1;
for (final String templateVariable : template.getTemplateVariables()) {
final String value = matchResult.group(i++);
encodedTemplateValues.addFirst(templateVariable, value);
if (decodedTemplateValues != null) {
decodedTemplateValues.addFirst(
UriComponent.decode(templateVariable, UriComponent.Type.PATH_SEGMENT),
UriComponent.decode(value, UriComponent.Type.PATH));
}
}
}
@Override
public String getFinalMatchingGroup() {
final MatchResult mr = matchResults.peek();
if (mr == null) {
return null;
}
final String finalGroup = mr.group(mr.groupCount());
// We have found a match but the right hand path pattern did not match anything
// so just returning an empty string as a final matching group result.
// Otherwise a non-empty patterns would fail to match the right-hand-path properly.
// See also PatternWithGroups.match(CharSequence) implementation.
return finalGroup == null ? "" : finalGroup;
}
@Override
public LinkedList getMatchedResults() {
return matchResults;
}
@Override
public void setEndpoint(final Endpoint endpoint) {
this.endpoint = endpoint;
}
@Override
public Endpoint getEndpoint() {
return endpoint;
}
@Override
public void setMatchedResourceMethod(final ResourceMethod resourceMethod) {
tracingLogger.get().log(ServerTraceEvent.MATCH_RESOURCE_METHOD, resourceMethod.getInvocable().getHandlingMethod());
this.matchedResourceMethod = resourceMethod;
}
@Override
public void pushMatchedRuntimeResource(final RuntimeResource runtimeResource) {
if (tracingLogger.get().isLogEnabled(ServerTraceEvent.MATCH_RUNTIME_RESOURCE)) {
tracingLogger.get().log(ServerTraceEvent.MATCH_RUNTIME_RESOURCE,
runtimeResource.getResources().get(0).getPath(),
runtimeResource.getResources().get(0).getPathPattern().getRegex(),
matchResults.peek().group()
.substring(0, matchResults.peek().group().length() - getFinalMatchingGroup().length()),
matchResults.peek().group());
}
this.matchedRuntimeResources.push(runtimeResource);
}
@Override
public void pushLocatorSubResource(final Resource subResourceFromLocator) {
this.locatorSubResources.push(subResourceFromLocator);
}
// UriInfo
private final ContainerRequest requestContext;
@Override
public URI getAbsolutePath() {
return requestContext.getAbsolutePath();
}
@Override
public UriBuilder getAbsolutePathBuilder() {
return new JerseyUriBuilder().uri(getAbsolutePath());
}
@Override
public URI getBaseUri() {
return requestContext.getBaseUri();
}
@Override
public UriBuilder getBaseUriBuilder() {
return new JerseyUriBuilder().uri(getBaseUri());
}
@Override
public List getMatchedResources() {
return Collections.unmodifiableList(matchedResources);
}
@Override
public List getMatchedURIs() {
return getMatchedURIs(true);
}
private static final Function PATH_DECODER = input -> UriComponent.decode(input, UriComponent.Type.PATH);
@Override
public List getMatchedURIs(final boolean decode) {
final List result;
if (decode) {
result = paths.stream().map(PATH_DECODER).collect(Collectors.toList());
} else {
result = paths;
}
return Collections.unmodifiableList(result);
}
@Override
public String getPath() {
return requestContext.getPath(true);
}
@Override
public String getPath(final boolean decode) {
return requestContext.getPath(decode);
}
@Override
public MultivaluedMap getPathParameters() {
return getPathParameters(true);
}
@Override
public MultivaluedMap getPathParameters(final boolean decode) {
if (decode) {
if (decodedTemplateValuesView != null) {
return decodedTemplateValuesView;
} else if (decodedTemplateValues == null) {
decodedTemplateValues = new MultivaluedHashMap<>();
for (final Map.Entry> e : encodedTemplateValues.entrySet()) {
decodedTemplateValues.put(
UriComponent.decode(e.getKey(), UriComponent.Type.PATH_SEGMENT),
// we need to keep the ability to add new entries
e.getValue().stream().map(s -> UriComponent.decode(s, UriComponent.Type.PATH))
.collect(Collectors.toCollection(ArrayList::new)));
}
}
decodedTemplateValuesView = new ImmutableMultivaluedMap<>(decodedTemplateValues);
return decodedTemplateValuesView;
} else {
return encodedTemplateValuesView;
}
}
@Override
public List getPathSegments() {
return getPathSegments(true);
}
@Override
public List getPathSegments(final boolean decode) {
final String requestPath = requestContext.getPath(false);
return Collections.unmodifiableList(UriComponent.decodePath(requestPath, decode));
}
@Override
public MultivaluedMap getQueryParameters() {
return getQueryParameters(true);
}
@Override
public MultivaluedMap getQueryParameters(final boolean decode) {
if (decode) {
if (decodedQueryParamsView != null) {
return decodedQueryParamsView;
}
decodedQueryParamsView =
new ImmutableMultivaluedMap<>(UriComponent.decodeQuery(getRequestUri(), true));
return decodedQueryParamsView;
} else {
if (encodedQueryParamsView != null) {
return encodedQueryParamsView;
}
encodedQueryParamsView =
new ImmutableMultivaluedMap<>(UriComponent.decodeQuery(getRequestUri(), false));
return encodedQueryParamsView;
}
}
/**
* Invalidate internal URI component cache views.
*
* This method needs to be called if request URI information changes.
*
*/
public void invalidateUriComponentViews() {
this.decodedQueryParamsView = null;
this.encodedQueryParamsView = null;
}
@Override
public URI getRequestUri() {
return requestContext.getRequestUri();
}
@Override
public UriBuilder getRequestUriBuilder() {
return UriBuilder.fromUri(getRequestUri());
}
// ExtendedUriInfo
@Override
public Throwable getMappedThrowable() {
return mappedThrowable;
}
@Override
public void setMappedThrowable(final Throwable mappedThrowable) {
this.mappedThrowable = mappedThrowable;
}
@Override
public List getMatchedTemplates() {
return Collections.unmodifiableList(templates);
}
@Override
public List getPathSegments(final String name) {
return getPathSegments(name, true);
}
@Override
public List getPathSegments(final String name, final boolean decode) {
final int[] bounds = getPathParameterBounds(name);
if (bounds != null) {
final String path = matchResults.getLast().group();
// Work out how many path segments are up to the start
// and end position of the matching path parameter value
// This assumes that the path always starts with a '/'
int segmentsStart = 0;
for (int x = 0; x < bounds[0]; x++) {
if (path.charAt(x) == '/') {
segmentsStart++;
}
}
int segmentsEnd = segmentsStart;
for (int x = bounds[0]; x < bounds[1]; x++) {
if (path.charAt(x) == '/') {
segmentsEnd++;
}
}
return getPathSegments(decode).subList(segmentsStart - 1, segmentsEnd);
} else {
return Collections.emptyList();
}
}
private int[] getPathParameterBounds(final String name) {
final Iterator templatesIterator = templates.iterator();
final Iterator matchResultsIterator = matchResults.iterator();
while (templatesIterator.hasNext()) {
MatchResult mr = matchResultsIterator.next();
// Find the index of path parameter
final int pIndex = getLastPathParameterIndex(name, templatesIterator.next());
if (pIndex != -1) {
int pathLength = mr.group().length();
int segmentIndex = mr.end(pIndex + 1);
final int groupLength = segmentIndex - mr.start(pIndex + 1);
// Find the absolute position of the end of the
// capturing group in the request path
while (matchResultsIterator.hasNext()) {
mr = matchResultsIterator.next();
segmentIndex += mr.group().length() - pathLength;
pathLength = mr.group().length();
}
return new int[] {segmentIndex - groupLength, segmentIndex};
}
}
return null;
}
private int getLastPathParameterIndex(final String name, final UriTemplate t) {
int i = 0;
int pIndex = -1;
for (final String parameterName : t.getTemplateVariables()) {
if (parameterName.equals(name)) {
pIndex = i;
}
i++;
}
return pIndex;
}
@Override
public Method getResourceMethod() {
return endpoint instanceof ResourceMethodInvoker
? ((ResourceMethodInvoker) endpoint).getResourceMethod() : null;
}
@Override
public Class> getResourceClass() {
return endpoint instanceof ResourceMethodInvoker
? ((ResourceMethodInvoker) endpoint).getResourceClass() : null;
}
@Override
public List getMatchedRuntimeResources() {
return this.matchedRuntimeResources;
}
@Override
public ResourceMethod getMatchedResourceMethod() {
return matchedResourceMethod;
}
@Override
public List getMatchedResourceLocators() {
return matchedLocators;
}
@Override
public List getLocatorSubResources() {
return locatorSubResources;
}
@Override
public Resource getMatchedModelResource() {
return matchedResourceMethod == null ? null : matchedResourceMethod.getParent();
}
@Override
public URI resolve(final URI uri) {
return UriTemplate.resolve(getBaseUri(), uri);
}
@Override
public URI relativize(URI uri) {
if (!uri.isAbsolute()) {
uri = resolve(uri);
}
return UriTemplate.relativize(getRequestUri(), uri);
}
}