001package org.javasimon; 002 003import org.javasimon.utils.SimonUtils; 004 005/** 006 * Matches Simon name patterns from configuration. Patterns can contain wildcard (*) that 007 * can be placed in following fashions: 008 * <ul> 009 * <li>empty string matches only {@link Manager#ROOT_SIMON_NAME} (root Simon) 010 * <li>{@code *} - matches anything 011 * <li>{@code something} - matches exactly {@code something} 012 * <li>{@code *something} - matches if tested name ends with {@code something} 013 * <li>{@code something*} - matches if tested name starts with {@code something} 014 * <li>{@code *something*} - matches if tested name contains {@code something} anywhere 015 * <li>{@code something*else} - matches if tested name starts with {@code something} and ends with {@code else} 016 * <li>anything else will throw {@link SimonException} with the message about invalid Simon pattern 017 * </ul> 018 * Without wildcard exact match is required. Every pattern with wildcards always matches with the same string 019 * without wildcards (in other words - wildcards matches with nothing as well). 020 */ 021public final class SimonPattern implements SimonFilter { 022 023 private static final String WILDCARD_STAR = "*"; 024 025 /** Expected Simon type. */ 026 private final Class<? extends Simon> expectedType; 027 028 /** Original pattern from the configuration. */ 029 private String pattern; 030 031 /** Used if complete match is expected. */ 032 private String all; 033 034 /** Used if head should match. */ 035 private String start; 036 037 /** Used if tail should match. */ 038 private String end; 039 040 /** Used if anything inside (or everything) should match. */ 041 private String middle; 042 043 private static final String INVALID_PATTERN = "Invalid Simon pattern: "; 044 045 /** 046 * Factory method that creates Simon name pattern - or returns {@code null} if parameter is {@code null}. 047 * 048 * @param pattern Simon name pattern as string 049 * @return Simon name pattern or {@code null} if pattern parameter is {@code null} 050 */ 051 public static SimonPattern create(String pattern) { 052 if (pattern == null) { 053 return null; 054 } 055 056 return createForType(pattern, Simon.class); 057 } 058 059 private static SimonPattern createForType(String pattern, Class<? extends Simon> expectedType) { 060 if (pattern == null) { 061 return new SimonPattern("*", expectedType); 062 } 063 return new SimonPattern(pattern, expectedType); 064 } 065 066 /** 067 * Factory method that creates Counter name pattern - or returns a pattern 068 * that accepts all Counters if parameter is {@code null}. 069 * 070 * @param pattern Counter name pattern as string 071 * @return Counter name pattern 072 */ 073 public static SimonPattern createForCounter(String pattern) { 074 return createForType(pattern, Counter.class); 075 } 076 077 /** 078 * Factory method that creates Stopwatch name pattern - or returns a pattern 079 * that accepts all Stopwatches if parameter is {@code null}. 080 * 081 * @param pattern Stopwatch name pattern as string 082 * @return Stopwatch name pattern 083 */ 084 public static SimonPattern createForStopwatch(String pattern) { 085 return createForType(pattern, Stopwatch.class); 086 } 087 088 /** 089 * Creates Simon name pattern used to match config file entries. 090 * 091 * @param pattern Simon name pattern 092 * @throws SimonException if pattern is not valid (runtime exception) 093 */ 094 public SimonPattern(String pattern) { 095 this(pattern, Simon.class); 096 } 097 098 /** 099 * Creates Simon pattern that used to match Simons of specified type with names that correspond to 100 * the pattern. 101 * 102 * @param pattern Simon name pattern 103 * @param expectedType expected type of Simon 104 * @throws SimonException if pattern is not valid (runtime exception) 105 */ 106 public SimonPattern(String pattern, Class<? extends Simon> expectedType) { 107 this.expectedType = expectedType; 108 this.pattern = pattern; 109 110 if (!pattern.contains(WILDCARD_STAR)) { 111 // no wildcard, we're going for complete match (all) 112 all = pattern; 113 validatePattern(all, pattern); 114 return; 115 } 116 if (pattern.equals(WILDCARD_STAR)) { 117 middle = ""; // everything contains this 118 return; 119 } 120 if (pattern.startsWith(WILDCARD_STAR) && pattern.endsWith(WILDCARD_STAR) && pattern.length() > 2) { 121 middle = pattern.substring(1, pattern.length() - 2); 122 validatePattern(middle, pattern); 123 return; 124 } 125 126 int ix = pattern.lastIndexOf('*'); 127 if (ix != pattern.indexOf('*')) { 128 throw new SimonException(INVALID_PATTERN + pattern); 129 } 130 if (!pattern.endsWith(WILDCARD_STAR)) { 131 end = pattern.substring(ix + 1); 132 validatePattern(end, pattern); 133 } 134 if (!pattern.startsWith(WILDCARD_STAR)) { 135 start = pattern.substring(0, ix); 136 validatePattern(start, pattern); 137 } 138 } 139 140 private void validatePattern(String simonNamePart, String pattern) { 141 if (!SimonUtils.checkName(simonNamePart)) { 142 throw new SimonException(INVALID_PATTERN + pattern); 143 } 144 } 145 146 @Override 147 /** 148 * Checks if Simon's name matches this pattern. 149 * 150 * @param simon Simon to be tested 151 * @return true if Simon's name matches this pattern 152 */ 153 public boolean accept(Simon simon) 154 { 155 return isCorrectType(simon) && matches(simon.getName()); 156 } 157 158 private boolean isCorrectType(Simon simon) { 159 return expectedType.isInstance(simon); 160 } 161 162 /** 163 * Checks if Simon name matches this pattern. 164 * 165 * @param name tested name 166 * @return true if tested pattern matches this pattern 167 */ 168 public boolean matches(String name) { 169 if (name == null) { 170 return pattern.equals(""); 171 } 172 if (all != null) { 173 return all.equals(name); 174 } 175 if (middle != null) { 176 return name.contains(middle); 177 } 178 if (start != null && !name.startsWith(start)) { 179 return false; 180 } 181 182 return end == null || name.endsWith(end); 183 } 184 185 @Override 186 public boolean equals(Object o) { 187 if (this == o) { 188 return true; 189 } 190 if (o == null || getClass() != o.getClass()) { 191 return false; 192 } 193 194 SimonPattern that = (SimonPattern) o; 195 196 if (pattern != null ? !pattern.equals(that.pattern) : that.pattern != null) { 197 return false; 198 } 199 200 if (expectedType != null ? !expectedType.equals(that.expectedType) : that.expectedType != null) { 201 return false; 202 } 203 204 return true; 205 } 206 207 @Override 208 public int hashCode() { 209 int result = expectedType != null ? expectedType.hashCode() : 0; 210 result = 31 * result + (pattern != null ? pattern.hashCode() : 0); 211 return result; 212 } 213 214 @Override 215 public String toString() { 216 return "SimonPattern {" + 217 "pattern='" + pattern + '\'' + 218 ", expectedType=" + expectedType + 219 '}'; 220 } 221}