blob: c66a540057f2e71b4173e284716b7b6ad112c343 [file] [log] [blame]
Jake Slack03928ae2014-05-13 18:41:56 -07001//
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}