001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.rest.util; 014 015import static org.apache.juneau.collections.JsonMap.*; 016import static org.apache.juneau.common.internal.StringUtils.*; 017 018import java.util.*; 019 020import org.apache.juneau.internal.*; 021 022/** 023 * Represents a URL path pattern match. 024 * 025 * For example, given the pattern <js>"/foo/{bar}/*"</js> and the path <js>"/foo/123/baz/qux"</js>, this match gives 026 * you a map containing <js>"{bar:123}"</js> and a remainder string containing <js>"baz/qux"</js>. 027 * 028 * <h5 class='section'>See Also:</h5><ul> 029 * </ul> 030 */ 031public class UrlPathMatch { 032 033 private final int matchedParts; 034 private final String path; 035 private final Map<String,String> vars; 036 037 /** 038 * Constructor. 039 * 040 * @param path The path being matched against. Can be <jk>null</jk>. 041 * @param matchedParts The number of parts that were matched against the path. 042 * @param keys The variable keys. Can be <jk>null</jk>. 043 * @param values The variable values. Can be <jk>null</jk>. 044 */ 045 protected UrlPathMatch(String path, int matchedParts, String[] keys, String[] values) { 046 this.path = path; 047 this.matchedParts = matchedParts; 048 this.vars = keys == null ? Collections.emptyMap() : new SimpleMap<>(keys, values); 049 } 050 051 /** 052 * Returns a map of the path variables and values. 053 * 054 * @return 055 * An unmodifiable map of variable keys/values. 056 * <br>Returns an empty map if no variables were found in the path. 057 */ 058 public Map<String,String> getVars() { 059 return vars; 060 } 061 062 /** 063 * Returns <jk>true</jk> if this match contains one or more variables. 064 * 065 * @return <jk>true</jk> if this match contains one or more variables. 066 */ 067 public boolean hasVars() { 068 return ! vars.isEmpty(); 069 } 070 071 /** 072 * Returns <jk>true</jk> if any of the variable values are blank. 073 * 074 * @return <jk>true</jk> if any of the variable values are blank. 075 */ 076 public boolean hasEmptyVars() { 077 for (String v : vars.values()) 078 if (isEmpty(v)) 079 return true; 080 return false; 081 } 082 083 /** 084 * Returns the remainder of the path after the pattern match has been made. 085 * 086 * <p> 087 * Same as {#link {@link #getSuffix()} but trims the leading slash if there is one. 088 * 089 * @return The remainder of the path after the pattern match has been made. 090 */ 091 public String getRemainder() { 092 String suffix = getSuffix(); 093 if (isNotEmpty(suffix) && suffix.charAt(0) == '/') 094 suffix = suffix.substring(1); 095 return suffix; 096 } 097 098 /** 099 * Returns the remainder of the URL after the pattern was matched. 100 * 101 * @return 102 * The remainder of the URL after the pattern was matched. 103 * <br>Can be <jk>null</jk> if nothing remains to be matched. 104 * <br>Otherwise, always starts with <js>'/'</js>. 105 */ 106 public String getSuffix() { 107 String s = path; 108 for (int j = 0; j < matchedParts; j++) { 109 int k = s.indexOf('/', 1); 110 if (k == -1) 111 return null; 112 s = s.substring(k); 113 } 114 return s; 115 } 116 117 /** 118 * Returns the part of the URL that the pattern matched against. 119 * 120 * @return 121 * The part of the URL that the pattern matched against. 122 * <br>Can be <jk>null</jk> if nothing matched. 123 * <br>Otherwise, always starts with <js>'/'</js>. 124 */ 125 public String getPrefix() { 126 int c = 0; 127 for (int j = 0; j < matchedParts; j++) { 128 c = path.indexOf('/', c+1); 129 if (c == -1) 130 c = path.length(); 131 } 132 return nullIfEmpty(path.substring(0, c)); 133 } 134 135 @Override /* Object */ 136 public String toString() { 137 return filteredMap() 138 .append("v", getVars()) 139 .append("r", getRemainder()) 140 .asString(); 141 } 142} 143