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.internal.StringUtils.*; 016 017import java.util.*; 018 019import org.apache.juneau.*; 020import org.apache.juneau.internal.*; 021import org.apache.juneau.marshall.*; 022 023/** 024 * Represents a URL path pattern match. 025 * 026 * For example, given the pattern <js>"/foo/{bar}/*"</js> and the path <js>"/foo/123/baz/qux"</js>, this match gives 027 * you a map containing <js>"{bar:123}"</js> and a remainder string containing <js>"baz/qux"</js>. 028 */ 029public class UrlPathPatternMatch { 030 031 private final int matchedParts; 032 private final String path; 033 private final Map<String,String> vars; 034 035 /** 036 * Constructor. 037 * 038 * @param path The path being matched against. Can be <jk>null</jk>. 039 * @param matchedParts The number of parts that were matched against the path. 040 * @param keys The variable keys. Can be <jk>null</jk>. 041 * @param values The variable values. Can be <jk>null</jk>. 042 */ 043 protected UrlPathPatternMatch(String path, int matchedParts, String[] keys, String[] values) { 044 this.path = path; 045 this.matchedParts = matchedParts; 046 this.vars = keys == null ? Collections.emptyMap() : new SimpleMap<>(keys, values); 047 } 048 049 /** 050 * Returns a map of the path variables and values. 051 * 052 * @return 053 * An unmodifiable map of variable keys/values. 054 * <br>Returns an empty map if no variables were found in the path. 055 */ 056 public Map<String,String> getVars() { 057 return vars; 058 } 059 060 /** 061 * Returns <jk>true</jk> if this match contains one or more variables. 062 * 063 * @return <jk>true</jk> if this match contains one or more variables. 064 */ 065 public boolean hasVars() { 066 return ! vars.isEmpty(); 067 } 068 069 070 /** 071 * Returns <jk>true</jk> if any of the variable values are blank. 072 * 073 * @return <jk>true</jk> if any of the variable values are blank. 074 */ 075 public boolean hasEmptyVars() { 076 for (String v : vars.values()) 077 if (isEmpty(v)) 078 return true; 079 return false; 080 } 081 082 /** 083 * Returns the remainder of the path after the pattern match has been made. 084 * 085 * @return The remainder of the path after the pattern match has been made. 086 */ 087 public String getRemainder() { 088 String suffix = getSuffix(); 089 if (isNotEmpty(suffix) && suffix.charAt(0) == '/') 090 suffix = suffix.substring(1); 091 return suffix; 092 } 093 094 /** 095 * Returns the remainder of the URL after the pattern was matched. 096 * 097 * @return 098 * The remainder of the URL after the pattern was matched. 099 * <br>Can be <jk>null</jk> if nothing remains to be matched. 100 * <br>Otherwise, always starts with <js>'/'</js>. 101 */ 102 public String getSuffix() { 103 String s = path; 104 for (int j = 0; j < matchedParts; j++) { 105 int k = s.indexOf('/', 1); 106 if (k == -1) 107 return null; 108 s = s.substring(k); 109 } 110 return s; 111 } 112 113 /** 114 * Returns the part of the URL that the pattern matched against. 115 * 116 * @return 117 * The part of the URL that the pattern matched against. 118 * <br>Can be <jk>null</jk> if nothing matched. 119 * <br>Otherwise, always starts with <js>'/'</js>. 120 */ 121 public String getPrefix() { 122 int c = 0; 123 for (int j = 0; j < matchedParts; j++) { 124 c = path.indexOf('/', c+1); 125 if (c == -1) 126 c = path.length(); 127 } 128 return nullIfEmpty(path.substring(0, c)); 129 } 130 131 /** 132 * Converts this object to a map. 133 * 134 * @return This object converted to a map. 135 */ 136 public ObjectMap toMap() { 137 return new DefaultFilteringObjectMap().append("v", getVars()).append("r", getRemainder()); 138 } 139 140 @Override /* Object */ 141 public String toString() { 142 return SimpleJson.DEFAULT.toString(toMap()); 143 } 144} 145