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