1// 2// ======================================================================== 3// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4// ------------------------------------------------------------------------ 5// All rights reserved. This program and the accompanying materials 6// are made available under the terms of the Eclipse Public License v1.0 7// and Apache License v2.0 which accompanies this distribution. 8// 9// The Eclipse Public License is available at 10// http://www.eclipse.org/legal/epl-v10.html 11// 12// The Apache License v2.0 is available at 13// http://www.opensource.org/licenses/apache2.0.php 14// 15// You may elect to redistribute this code under either of these licenses. 16// ======================================================================== 17// 18 19 20package org.eclipse.jetty.webapp; 21 22import java.util.ArrayList; 23import java.util.List; 24import java.util.StringTokenizer; 25 26 27/* ------------------------------------------------------------ */ 28/** 29 * ClasspathPattern performs sequential pattern matching of a class name 30 * against an internal array of classpath pattern entries. 31 * 32 * When an entry starts with '-' (minus), reverse matching is performed. 33 * When an entry ends with '.' (period), prefix matching is performed. 34 * 35 * When class is initialized from a classpath pattern string, entries 36 * in this string should be separated by ':' (semicolon) or ',' (comma). 37 */ 38 39public class ClasspathPattern 40{ 41 private static class Entry 42 { 43 public String classpath = null; 44 public boolean result = false; 45 public boolean partial = false; 46 } 47 48 final private List<String> _patterns = new ArrayList<String>(); 49 final private List<Entry> _entries = new ArrayList<Entry>(); 50 51 /* ------------------------------------------------------------ */ 52 public ClasspathPattern() 53 { 54 } 55 56 /* ------------------------------------------------------------ */ 57 public ClasspathPattern(String[] patterns) 58 { 59 setPatterns(patterns); 60 } 61 62 /* ------------------------------------------------------------ */ 63 public ClasspathPattern(String pattern) 64 { 65 setPattern(pattern); 66 } 67 68 69 /* ------------------------------------------------------------ */ 70 /** 71 * Initialize the matcher by parsing each classpath pattern in an array 72 * 73 * @param patterns array of classpath patterns 74 */ 75 private void setPatterns(String[] patterns) 76 { 77 _patterns.clear(); 78 _entries.clear(); 79 addPatterns(patterns); 80 } 81 82 /* ------------------------------------------------------------ */ 83 /** 84 * Initialize the matcher by parsing each classpath pattern in an array 85 * 86 * @param patterns array of classpath patterns 87 */ 88 private void addPatterns(String[] patterns) 89 { 90 if (patterns != null) 91 { 92 Entry entry = null; 93 for (String pattern : patterns) 94 { 95 entry = createEntry(pattern); 96 if (entry != null) { 97 _patterns.add(pattern); 98 _entries.add(entry); 99 } 100 } 101 } 102 } 103 104 /* ------------------------------------------------------------ */ 105 /** 106 * Create an entry object containing information about 107 * a single classpath pattern 108 * 109 * @param pattern single classpath pattern 110 * @return corresponding Entry object 111 */ 112 private Entry createEntry(String pattern) 113 { 114 Entry entry = null; 115 116 if (pattern != null) 117 { 118 String item = pattern.trim(); 119 if (item.length() > 0) 120 { 121 entry = new Entry(); 122 entry.result = !item.startsWith("-"); 123 entry.partial = item.endsWith("."); 124 entry.classpath = entry.result ? item : item.substring(1).trim(); 125 } 126 } 127 return entry; 128 } 129 130 /* ------------------------------------------------------------ */ 131 /** 132 * Initialize the matcher by parsing a classpath pattern string 133 * 134 * @param pattern classpath pattern string 135 */ 136 public void setPattern(String pattern) 137 { 138 _patterns.clear(); 139 _entries.clear(); 140 addPattern(pattern); 141 } 142 143 /* ------------------------------------------------------------ */ 144 /** 145 * Parse a classpath pattern string and appending the result 146 * to the existing configuration. 147 * 148 * @param pattern classpath pattern string 149 */ 150 public void addPattern(String pattern) 151 { 152 ArrayList<String> patterns = new ArrayList<String>(); 153 StringTokenizer entries = new StringTokenizer(pattern, ":,"); 154 while (entries.hasMoreTokens()) 155 { 156 patterns.add(entries.nextToken()); 157 } 158 159 addPatterns((String[])patterns.toArray(new String[patterns.size()])); 160 } 161 162 /* ------------------------------------------------------------ */ 163 /** 164 * @return array of classpath patterns 165 */ 166 public String[] getPatterns() 167 { 168 String[] patterns = null; 169 170 if (_patterns!=null && _patterns.size() > 0) 171 { 172 patterns = _patterns.toArray(new String[_patterns.size()]); 173 } 174 175 return patterns; 176 } 177 178 /* ------------------------------------------------------------ */ 179 /** 180 * Match the class name against the pattern 181 * 182 * @param name name of the class to match 183 * @return true if class matches the pattern 184 */ 185 public boolean match(String name) 186 { 187 boolean result=false; 188 189 if (_entries != null) 190 { 191 name = name.replace('/','.'); 192 193 int startIndex = 0; 194 195 while(startIndex < name.length() && name.charAt(startIndex) == '.') { 196 startIndex++; 197 } 198 199 int dollar = name.indexOf("$"); 200 201 int endIndex = dollar != -1 ? dollar : name.length(); 202 203 for (Entry entry : _entries) 204 { 205 if (entry != null) 206 { 207 if (entry.partial) 208 { 209 if (name.regionMatches(startIndex, entry.classpath, 0, entry.classpath.length())) 210 { 211 result = entry.result; 212 break; 213 } 214 } 215 else 216 { 217 int regionLength = endIndex-startIndex; 218 if (regionLength == entry.classpath.length() 219 && name.regionMatches(startIndex, entry.classpath, 0, regionLength)) 220 { 221 result = entry.result; 222 break; 223 } 224 } 225 } 226 } 227 } 228 return result; 229 } 230} 231