View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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  
20  package org.eclipse.jetty.webapp;
21  
22  import java.util.ArrayList;
23  import java.util.List;
24  import 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  
39  public 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       * @param patterns array of classpath patterns
85       */
86      private void addPatterns(String[] patterns)
87      {
88          if (patterns != null)
89          {
90              Entry entry = null; 
91              for (String pattern : patterns)
92              {
93                  entry = createEntry(pattern);
94                  if (entry != null) 
95                  {
96                      _patterns.add(pattern);
97                      _entries.add(entry);
98                  }
99              }
100         }
101     }
102     
103     /* ------------------------------------------------------------ */
104     /**
105      * @param patterns array of classpath patterns
106      */
107     private void prependPatterns(String[] patterns)
108     {
109         if (patterns != null)
110         {
111             Entry entry = null;
112             int i=0;
113             for (String pattern : patterns)
114             {
115                 entry = createEntry(pattern);
116                 if (entry != null) 
117                 {
118                     _patterns.add(i,pattern);
119                     _entries.add(i,entry);
120                     i++;
121                 }
122             }
123         }
124     }
125     
126     /* ------------------------------------------------------------ */
127     /**
128      * Create an entry object containing information about 
129      * a single classpath pattern
130      * 
131      * @param pattern single classpath pattern
132      * @return corresponding Entry object
133      */
134     private Entry createEntry(String pattern)
135     {
136         Entry entry = null;
137         
138         if (pattern != null)
139         {
140             String item = pattern.trim();
141             if (item.length() > 0)
142             {
143                 entry = new Entry();
144                 entry.result = !item.startsWith("-");
145                 entry.partial = item.endsWith(".");
146                 entry.classpath = entry.result ? item : item.substring(1).trim();
147             }
148         }
149         return entry;
150     }
151     
152     /* ------------------------------------------------------------ */
153     /**
154      * Initialize the matcher by parsing a classpath pattern string
155      * 
156      * @param pattern classpath pattern string
157      */
158     public void setPattern(String pattern)
159     {
160         _patterns.clear();
161         _entries.clear();
162         addPattern(pattern);
163     }
164 
165     /* ------------------------------------------------------------ */
166     /**
167      * Parse a classpath pattern string and appending the result
168      * to the existing configuration.
169      * 
170      * @param pattern classpath pattern string
171      */
172     public void addPattern(String pattern)
173     {
174         ArrayList<String> patterns = new ArrayList<String>();
175         StringTokenizer entries = new StringTokenizer(pattern, ":,");
176         while (entries.hasMoreTokens())
177         {
178             patterns.add(entries.nextToken());
179         }
180         
181         addPatterns(patterns.toArray(new String[patterns.size()]));
182     }   
183     
184 
185     /* ------------------------------------------------------------ */
186     public void prependPattern(String classOrPackage)
187     {
188         ArrayList<String> patterns = new ArrayList<String>();
189         StringTokenizer entries = new StringTokenizer(classOrPackage, ":,");
190         while (entries.hasMoreTokens())
191         {
192             patterns.add(entries.nextToken());
193         }
194         
195         prependPatterns(patterns.toArray(new String[patterns.size()]));
196     }
197     
198     
199     /* ------------------------------------------------------------ */
200     /**
201      * @return array of classpath patterns
202      */
203     public String[] getPatterns()
204     {
205         String[] patterns = null;
206         
207         if (_patterns!=null && _patterns.size() > 0)
208         {
209             patterns = _patterns.toArray(new String[_patterns.size()]);
210         }
211         
212         return patterns;
213     }
214     
215     /* ------------------------------------------------------------ */
216     /**
217      * Match the class name against the pattern
218      *
219      * @param name name of the class to match
220      * @return true if class matches the pattern
221      */
222     public boolean match(String name)
223     {       
224         boolean result=false;
225 
226         if (_entries != null)
227         {
228             name = name.replace('/','.');
229 
230             int startIndex = 0;
231 
232             while(startIndex < name.length() && name.charAt(startIndex) == '.') {
233                 startIndex++;
234             }
235 
236             int dollar = name.indexOf("$");
237 
238             int endIndex =  dollar != -1 ? dollar : name.length();
239 
240             for (Entry entry : _entries)
241             {
242                 if (entry != null)
243                 {               
244                     if (entry.partial)
245                     {
246                         if (name.regionMatches(startIndex, entry.classpath, 0, entry.classpath.length()))
247                         {
248                             result = entry.result;
249                             break;
250                         }
251                     }
252                     else
253                     {
254                         int regionLength = endIndex-startIndex;
255                         if (regionLength == entry.classpath.length()
256                                 && name.regionMatches(startIndex, entry.classpath, 0, regionLength))
257                         {
258                             result = entry.result;
259                             break;
260                         }
261                     }
262                 }
263             }
264         }
265         return result;
266     }
267 
268 }