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