/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.cxf.jaxrs.impl; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Logger; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.PathSegment; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import org.apache.cxf.common.logging.LogUtils; import org.apache.cxf.jaxrs.model.MethodInvocationInfo; import org.apache.cxf.jaxrs.model.OperationResourceInfo; import org.apache.cxf.jaxrs.model.OperationResourceInfoStack; import org.apache.cxf.jaxrs.model.URITemplate; import org.apache.cxf.jaxrs.utils.HttpUtils; import org.apache.cxf.jaxrs.utils.JAXRSUtils; import org.apache.cxf.message.Message; import org.apache.cxf.message.MessageUtils; public class UriInfoImpl implements UriInfo { private static final Logger LOG = LogUtils.getL7dLogger(UriInfoImpl.class); private static final String CASE_INSENSITIVE_QUERIES = "org.apache.cxf.http.case_insensitive_queries"; private static final String PARSE_QUERY_VALUE_AS_COLLECTION = "parse.query.value.as.collection"; private MultivaluedMap<String, String> templateParams; private Message message; private OperationResourceInfoStack stack; private boolean caseInsensitiveQueries; private boolean queryValueIsCollection; @SuppressWarnings("unchecked") public UriInfoImpl(Message m) { this(m, (MultivaluedMap<String, String>)m.get(URITemplate.TEMPLATE_PARAMETERS)); } public UriInfoImpl(Message m, MultivaluedMap<String, String> templateParams) { this.message = m; this.templateParams = templateParams; if (m != null) { this.stack = m.get(OperationResourceInfoStack.class); this.caseInsensitiveQueries = MessageUtils.isTrue(m.getContextualProperty(CASE_INSENSITIVE_QUERIES)); this.queryValueIsCollection = MessageUtils.isTrue(m.getContextualProperty(PARSE_QUERY_VALUE_AS_COLLECTION)); } } public URI getAbsolutePath() { String path = getAbsolutePathAsString(); return URI.create(path); } public UriBuilder getAbsolutePathBuilder() { return new UriBuilderImpl(getAbsolutePath()); } public URI getBaseUri() { URI u = URI.create(HttpUtils.getEndpointAddress(message)); return HttpUtils.toAbsoluteUri(u, message); } public UriBuilder getBaseUriBuilder() { return new UriBuilderImpl(getBaseUri()); } public String getPath() { return getPath(true); } public String getPath(boolean decode) { String value = doGetPath(decode, true); if (value.length() > 1 && value.startsWith("/")) { return value.substring(1); } else { return value; } } public List<PathSegment> getPathSegments() { return getPathSegments(true); } public List<PathSegment> getPathSegments(boolean decode) { return JAXRSUtils.getPathSegments(getPath(false), decode); } public MultivaluedMap<String, String> getQueryParameters() { return getQueryParameters(true); } public MultivaluedMap<String, String> getQueryParameters(boolean decode) { MultivaluedMap<String, String> queries = !caseInsensitiveQueries ? new MetadataMap<String, String>() : new MetadataMap<String, String>(false, true); JAXRSUtils.getStructuredParams(queries, (String)message.get(Message.QUERY_STRING), "&", decode, decode, queryValueIsCollection); return queries; } public URI getRequestUri() { String path = getAbsolutePathAsString(); String queries = (String)message.get(Message.QUERY_STRING); if (queries != null) { path += "?" + queries; } return URI.create(path); } public UriBuilder getRequestUriBuilder() { return new UriBuilderImpl(getRequestUri()); } public MultivaluedMap<String, String> getPathParameters() { return getPathParameters(true); } public MultivaluedMap<String, String> getPathParameters(boolean decode) { MetadataMap<String, String> values = new MetadataMap<String, String>(); if (templateParams == null) { return values; } for (Map.Entry<String, List<String>> entry : templateParams.entrySet()) { if (entry.getKey().equals(URITemplate.FINAL_MATCH_GROUP)) { continue; } values.add(entry.getKey(), decode ? HttpUtils.pathDecode(entry.getValue().get(0)) : entry .getValue().get(0)); } return values; } public List<Object> getMatchedResources() { if (stack != null) { List<Object> resources = new LinkedList<Object>(); for (MethodInvocationInfo invocation : stack) { resources.add(0, invocation.getRealClass()); } return resources; } LOG.fine("No resource stack information, returning empty list"); return Collections.emptyList(); } public List<String> getMatchedURIs() { return getMatchedURIs(true); } public List<String> getMatchedURIs(boolean decode) { if (stack != null) { List<String> objects = new ArrayList<>(); List<String> uris = new LinkedList<String>(); StringBuilder sumPath = new StringBuilder(""); for (MethodInvocationInfo invocation : stack) { List<String> templateObjects = invocation.getTemplateValues(); OperationResourceInfo ori = invocation.getMethodInfo(); URITemplate[] paths = { ori.getClassResourceInfo().getURITemplate(), ori.getURITemplate() }; if (paths[0] != null) { int count = paths[0].getVariables().size(); List<String> rootObjects = new ArrayList<>(count); for (int i = 0; i < count && i < templateObjects.size(); i++) { rootObjects.add(templateObjects.get(i)); } uris.add(0, createMatchedPath(paths[0].getValue(), rootObjects, decode)); } for (URITemplate t : paths) { if (t != null) { sumPath.append("/").append(t.getValue()); } } objects.addAll(templateObjects); uris.add(0, createMatchedPath(sumPath.toString(), objects, decode)); } return uris; } LOG.fine("No resource stack information, returning empty list"); return Collections.emptyList(); } private static String createMatchedPath(String uri, List<? extends Object> vars, boolean decode) { String uriPath = UriBuilder.fromPath(uri).buildFromEncoded(vars.toArray()).getRawPath(); return decode ? HttpUtils.pathDecode(uriPath) : uriPath; } private String doGetPath(boolean decode, boolean addSlash) { String path = HttpUtils.getPathToMatch(message, addSlash); return decode ? HttpUtils.pathDecode(path) : path; } private String getAbsolutePathAsString() { String address = getBaseUri().toString(); if (MessageUtils.isRequestor(message)) { return address; } String path = doGetPath(false, false); if (path.startsWith("/") && address.endsWith("/")) { address = address.substring(0, address.length() - 1); } if (!path.isEmpty() && !path.startsWith("/") && !address.endsWith("/")) { address = address + "/"; } return address + path; } @Override public URI relativize(URI uri) { URI resolved = HttpUtils.resolve(getBaseUriBuilder(), uri); return HttpUtils.relativize(getRequestUri(), resolved); } @Override public URI resolve(URI uri) { return HttpUtils.resolve(getBaseUriBuilder(), uri); } }