View Javadoc

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  
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       * 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 }