1 /* 2 * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package de.smartics.properties.spi.config.domain.key; 17 18 import java.io.Serializable; 19 import java.util.ArrayList; 20 import java.util.List; 21 22 import org.apache.commons.lang.StringUtils; 23 24 import de.smartics.properties.api.config.domain.key.ConfigurationKey; 25 import de.smartics.util.lang.Arg; 26 27 /** 28 * Matches a path that may contain wildcards at the end of the path. 29 */ 30 public final class PathMatcher implements PropertiesResourceMatcher 31 { 32 // ********************************* Fields ********************************* 33 34 // --- constants ------------------------------------------------------------ 35 36 /** 37 * The class version identifier. 38 * <p> 39 * The value of this constant is {@value}. 40 * </p> 41 */ 42 private static final long serialVersionUID = 1L; 43 44 // --- members -------------------------------------------------------------- 45 46 /** 47 * The configuration key the matcher is responsible for. 48 * 49 * @serial 50 */ 51 private final ConfigurationKey<?> configurationKey; 52 53 /** 54 * The list of matchers to consult in the given order. 55 * 56 * @serial 57 */ 58 private final List<Matcher> matchers; 59 60 // ****************************** Initializer ******************************* 61 62 // ****************************** Constructors ****************************** 63 64 /** 65 * Default constructor. 66 * 67 * @param configurationKey the configuration key the matcher is responsible 68 * for. 69 * @param matchers the matchers to use for matching. 70 */ 71 private PathMatcher(final ConfigurationKey<?> configurationKey, 72 final List<Matcher> matchers) 73 { 74 this.configurationKey = configurationKey; 75 this.matchers = matchers; 76 } 77 78 // ****************************** Inner Classes ***************************** 79 80 /** 81 * Matcher of a single path. 82 */ 83 public static final class Matcher implements Serializable 84 { 85 // ******************************** Fields ******************************** 86 87 // --- constants ---------------------------------------------------------- 88 89 /** 90 * The class version identifier. 91 * <p> 92 * The value of this constant is {@value}. 93 * </p> 94 */ 95 private static final long serialVersionUID = 1L; 96 97 // --- members ------------------------------------------------------------ 98 99 /** 100 * The path to match. 101 * 102 * @serial 103 */ 104 private final String path; 105 106 /** 107 * The flag to indicate whether {@code path} is a prefix to be match ( 108 * <code>true</code>) or if it is an exact match (<code>false</code>). 109 * 110 * @serial 111 */ 112 private final boolean wildcardMatch; 113 114 // ***************************** Initializer ****************************** 115 116 // ***************************** Constructors ***************************** 117 118 /** 119 * Default constructor. 120 * 121 * @param path the path to match. 122 */ 123 public Matcher(final String path) 124 { 125 this.wildcardMatch = Arg.checkNotNull("path", path).endsWith("*"); 126 this.path = wildcardMatch ? StringUtils.chop(path) : path; 127 } 128 129 // ***************************** Inner Classes **************************** 130 131 // ******************************** Methods ******************************* 132 133 // --- init --------------------------------------------------------------- 134 135 // --- get&set ------------------------------------------------------------ 136 137 // --- business ----------------------------------------------------------- 138 139 private boolean match(final String id) 140 { 141 final boolean match = 142 wildcardMatch ? id.startsWith(path) : id.equals(path); 143 return match; 144 } 145 146 // --- object basics ------------------------------------------------------ 147 148 /** 149 * Returns the string representation of the object. 150 * 151 * @return the string representation of the object. 152 */ 153 @Override 154 public String toString() 155 { 156 final StringBuilder buffer = new StringBuilder(); 157 158 buffer.append(path); 159 160 if (wildcardMatch) 161 { 162 buffer.append("*"); 163 } 164 165 return buffer.toString(); 166 } 167 } 168 169 // ********************************* Methods ******************************** 170 171 // --- factories ------------------------------------------------------------ 172 173 /** 174 * Constructs an instance based on the given paths. 175 * 176 * @param configurationKey the configuration key the matcher is responsible 177 * for. 178 * @param paths the list of paths to match. A path may end with <code>*</code> 179 * signaling a wildcard match. 180 * @return the constructed instance. 181 */ 182 public static PathMatcher forPaths( 183 final ConfigurationKey<?> configurationKey, final List<String> paths) 184 { 185 return forMatchers(configurationKey, convertToMatchers(paths)); 186 } 187 188 /** 189 * Constructs an instance based on the given matchers. 190 * 191 * @param configurationKey the configuration key the matcher is responsible 192 * for. 193 * @param matchers the matchers to use for matching. 194 * @return the constructed instance. 195 */ 196 public static PathMatcher forMatchers( 197 final ConfigurationKey<?> configurationKey, final List<Matcher> matchers) 198 { 199 return new PathMatcher(configurationKey, matchers); 200 } 201 202 // --- init ----------------------------------------------------------------- 203 204 private static List<Matcher> convertToMatchers(final List<String> paths) 205 { 206 final List<Matcher> matchers = new ArrayList<Matcher>(paths.size()); 207 208 for (final String path : paths) 209 { 210 final Matcher matcher = new Matcher(path); 211 matchers.add(matcher); 212 } 213 214 return matchers; 215 } 216 217 // --- get&set -------------------------------------------------------------- 218 219 /** 220 * Returns the configuration key the matcher is responsible for. 221 * 222 * @return the configuration key the matcher is responsible for. 223 */ 224 @Override 225 public ConfigurationKey<?> getConfigurationKey() 226 { 227 return configurationKey; 228 } 229 230 // --- business ------------------------------------------------------------- 231 232 @Override 233 public boolean match(final String id) 234 { 235 for (final Matcher matcher : matchers) 236 { 237 final boolean match = matcher.match(id); 238 if (match) 239 { 240 return true; 241 } 242 } 243 return false; 244 } 245 246 // --- object basics -------------------------------------------------------- 247 248 /** 249 * Returns the string representation of the object. 250 * 251 * @return the string representation of the object. 252 */ 253 @Override 254 public String toString() 255 { 256 final StringBuilder buffer = new StringBuilder(); 257 258 buffer.append(configurationKey).append(':'); 259 260 for (final Matcher matcher : matchers) 261 { 262 buffer.append(' ').append(matcher); 263 } 264 265 return buffer.toString(); 266 } 267 }