KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > atlassian > seraph > util > PathMapper


1 /*
2  * Created by IntelliJ IDEA.
3  * User: Administrator
4  * Date: 19/02/2002
5  * Time: 11:29:22
6  * To change template for new class use
7  * Code Style | Class Templates options (Tools | IDE Options).
8  */

9
10 /*
11  * Title: PathMapper
12  * Description:
13  *
14  * This software is published under the terms of the OpenSymphony Software
15  * License version 1.1, of which a copy has been included with this
16  * distribution in the LICENSE.txt file.
17  */

18 package com.atlassian.seraph.util;
19
20 import java.io.Serializable JavaDoc;
21 import java.util.*;
22
23 /**
24  * The PathMapper is used to map file patterns to keys, and find an approriate
25  * key for a given file path. The pattern rules are consistent with those defined
26  * in the Servlet 2.3 API on the whole. Wildcard patterns are also supported, using
27  * any combination of * and ?.
28  *
29  * <h3>Example</h3>
30  *
31  * <blockquote><code>
32  * PathMapper pm = new PathMapper();<br>
33  * <br>
34  * pm.put("one","/");<br>
35  * pm.put("two","/mydir/*");<br>
36  * pm.put("three","*.xml");<br>
37  * pm.put("four","/myexactfile.html");<br>
38  * pm.put("five","/*\/admin/*.??ml");<br>
39  * <br>
40  * String result1 = pm.get("/mydir/myfile.xml"); // returns "two";<br>
41  * String result2 = pm.get("/mydir/otherdir/admin/myfile.html"); // returns "five";<br>
42  * </code></blockquote>
43  *
44  * @author <a HREF="mailto:joe@truemesh.com">Joe Walnes</a>
45  * @author <a HREF="mailto:mike@atlassian.com">Mike Cannon-Brookes</a>
46  * @author <a HREF="mailto:hani@formicary.net">Hani Suleiman</a>
47  * @version $Revision: 1.1 $
48  */

49 public class PathMapper implements Serializable JavaDoc
50 {
51     private Map mappings = new HashMap();
52     private List complexPaths = new ArrayList();
53     static String JavaDoc[] DEFAULT_KEYS = {"/", "*", "/*"};
54
55     /** Add a key and appropriate matching pattern. */
56     public void put(String JavaDoc key, String JavaDoc pattern)
57     {
58         mappings.put(pattern, key);
59         if (pattern.indexOf('?') > -1 || (pattern.indexOf("*") > -1 && pattern.length() > 1))
60         {
61             complexPaths.add(pattern);
62         }
63     }
64
65
66     /** Retrieve appropriate key by matching patterns with supplied path. */
67     public String JavaDoc get(String JavaDoc path)
68     {
69         if (path == null) path = "/";
70         String JavaDoc mapped = findKey(path, mappings, complexPaths);
71         if (mapped == null) return null;
72         return (String JavaDoc) mappings.get(mapped);
73     }
74
75
76     /** Retrieve all mappings which match a supplied path. */
77     public Collection getAll(String JavaDoc path)
78     {
79         if (path == null) path = "/";
80
81         List matches = new ArrayList();
82
83         // find exact keys
84
String JavaDoc exactKey = findExactKey(path, mappings);
85
86         if (exactKey != null)
87             matches.add(mappings.get(exactKey));
88
89         // find complex keys
90
for (Iterator iterator = findComplexKeys(path, complexPaths).iterator(); iterator.hasNext();)
91         {
92             String JavaDoc mapped = (String JavaDoc) iterator.next();
93             matches.add(mappings.get(mapped));
94         }
95
96         // find default keys
97
for (Iterator iterator = findDefaultKeys(mappings).iterator(); iterator.hasNext();)
98         {
99             String JavaDoc mapped = (String JavaDoc) iterator.next();
100             matches.add(mappings.get(mapped));
101         }
102
103         return matches;
104     }
105
106
107     /** Find exact key in mappings. */
108     private static String JavaDoc findKey(String JavaDoc path, Map mappings, List keys)
109     {
110         String JavaDoc result = findExactKey(path, mappings);
111         if (result == null) result = findComplexKey(path, keys);
112         if (result == null) result = findDefaultKey(mappings);
113         return result;
114     }
115
116
117     /** Check if path matches exact pattern ( /blah/blah.jsp ). */
118     private static String JavaDoc findExactKey(String JavaDoc path, Map mappings)
119     {
120         if (mappings.containsKey(path)) return path;
121         return null;
122     }
123
124
125     /** Find single matching complex key */
126     private static String JavaDoc findComplexKey(String JavaDoc path, List complexPaths)
127     {
128         int size = complexPaths.size();
129         for (int i = 0; i < size; i++)
130         {
131             String JavaDoc key = (String JavaDoc) complexPaths.get(i);
132             if (match(key, path, false))
133             {
134                 return key;
135             }
136         }
137         return null;
138     }
139
140     /** Find all matching complex keys */
141     private static Collection findComplexKeys(String JavaDoc path, List complexPaths)
142     {
143         int size = complexPaths.size();
144         List matches = new ArrayList();
145         for (int i = 0; i < size; i++)
146         {
147             String JavaDoc key = (String JavaDoc) complexPaths.get(i);
148             if (match(key, path, false))
149             {
150                 matches.add(key);
151             }
152         }
153         return matches;
154     }
155
156     /** Look for root pattern ( / ). */
157     private static String JavaDoc findDefaultKey(Map mappings)
158     {
159         for (int i = 0; i < DEFAULT_KEYS.length; i++)
160         {
161             if (mappings.containsKey(DEFAULT_KEYS[i])) return DEFAULT_KEYS[i];
162         }
163         return null;
164     }
165
166     /** Look for root patterns ( / ). */
167     private static Collection findDefaultKeys(Map mappings)
168     {
169         List matches = new ArrayList();
170
171         for (int i = 0; i < DEFAULT_KEYS.length; i++)
172         {
173             if (mappings.containsKey(DEFAULT_KEYS[i]))
174                 matches.add(DEFAULT_KEYS[i]);
175         }
176
177         return matches;
178     }
179
180
181     private static boolean match(String JavaDoc pattern, String JavaDoc str, boolean isCaseSensitive)
182     {
183         char[] patArr = pattern.toCharArray();
184         char[] strArr = str.toCharArray();
185         int patIdxStart = 0;
186         int patIdxEnd = patArr.length - 1;
187         int strIdxStart = 0;
188         int strIdxEnd = strArr.length - 1;
189         char ch;
190
191         boolean containsStar = false;
192         for (int i = 0; i < patArr.length; i++)
193         {
194             if (patArr[i] == '*')
195             {
196                 containsStar = true;
197                 break;
198             }
199         }
200
201         if (!containsStar)
202         {
203             // No '*'s, so we make a shortcut
204
if (patIdxEnd != strIdxEnd)
205             {
206                 return false; // Pattern and string do not have the same size
207
}
208             for (int i = 0; i <= patIdxEnd; i++)
209             {
210                 ch = patArr[i];
211                 if (ch != '?')
212                 {
213                     if (isCaseSensitive && ch != strArr[i])
214                     {
215                         return false;// Character mismatch
216
}
217                     if (!isCaseSensitive && Character.toUpperCase(ch) !=
218                             Character.toUpperCase(strArr[i]))
219                     {
220                         return false; // Character mismatch
221
}
222                 }
223             }
224             return true; // String matches against pattern
225
}
226
227         if (patIdxEnd == 0)
228         {
229             return true; // Pattern contains only '*', which matches anything
230
}
231
232         // Process characters before first star
233
while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd)
234         {
235             if (ch != '?')
236             {
237                 if (isCaseSensitive && ch != strArr[strIdxStart])
238                 {
239                     return false;// Character mismatch
240
}
241                 if (!isCaseSensitive && Character.toUpperCase(ch) !=
242                         Character.toUpperCase(strArr[strIdxStart]))
243                 {
244                     return false;// Character mismatch
245
}
246             }
247             patIdxStart++;
248             strIdxStart++;
249         }
250         if (strIdxStart > strIdxEnd)
251         {
252             // All characters in the string are used. Check if only '*'s are
253
// left in the pattern. If so, we succeeded. Otherwise failure.
254
for (int i = patIdxStart; i <= patIdxEnd; i++)
255             {
256                 if (patArr[i] != '*')
257                 {
258                     return false;
259                 }
260             }
261             return true;
262         }
263
264         // Process characters after last star
265
while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd)
266         {
267             if (ch != '?')
268             {
269                 if (isCaseSensitive && ch != strArr[strIdxEnd])
270                 {
271                     return false;// Character mismatch
272
}
273                 if (!isCaseSensitive && Character.toUpperCase(ch) !=
274                         Character.toUpperCase(strArr[strIdxEnd]))
275                 {
276                     return false;// Character mismatch
277
}
278             }
279             patIdxEnd--;
280             strIdxEnd--;
281         }
282         if (strIdxStart > strIdxEnd)
283         {
284             // All characters in the string are used. Check if only '*'s are
285
// left in the pattern. If so, we succeeded. Otherwise failure.
286
for (int i = patIdxStart; i <= patIdxEnd; i++)
287             {
288                 if (patArr[i] != '*')
289                 {
290                     return false;
291                 }
292             }
293             return true;
294         }
295
296         // process pattern between stars. padIdxStart and patIdxEnd point
297
// always to a '*'.
298
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd)
299         {
300             int patIdxTmp = -1;
301             for (int i = patIdxStart + 1; i <= patIdxEnd; i++)
302             {
303                 if (patArr[i] == '*')
304                 {
305                     patIdxTmp = i;
306                     break;
307                 }
308             }
309             if (patIdxTmp == patIdxStart + 1)
310             {
311                 // Two stars next to each other, skip the first one.
312
patIdxStart++;
313                 continue;
314             }
315             // Find the pattern between padIdxStart & padIdxTmp in str between
316
// strIdxStart & strIdxEnd
317
int patLength = (patIdxTmp - patIdxStart - 1);
318             int strLength = (strIdxEnd - strIdxStart + 1);
319             int foundIdx = -1;
320             strLoop:
321             for (int i = 0; i <= strLength - patLength; i++)
322             {
323                 for (int j = 0; j < patLength; j++)
324                 {
325                     ch = patArr[patIdxStart + j + 1];
326                     if (ch != '?')
327                     {
328                         if (isCaseSensitive && ch != strArr[strIdxStart + i + j])
329                         {
330                             continue strLoop;
331                         }
332                         if (!isCaseSensitive && Character.toUpperCase(ch) !=
333                                 Character.toUpperCase(strArr[strIdxStart + i + j]))
334                         {
335                             continue strLoop;
336                         }
337                     }
338                 }
339
340                 foundIdx = strIdxStart + i;
341                 break;
342             }
343
344             if (foundIdx == -1)
345             {
346                 return false;
347             }
348
349             patIdxStart = patIdxTmp;
350             strIdxStart = foundIdx + patLength;
351         }
352
353         // All characters in the string are used. Check if only '*'s are left
354
// in the pattern. If so, we succeeded. Otherwise failure.
355
for (int i = patIdxStart; i <= patIdxEnd; i++)
356         {
357             if (patArr[i] != '*')
358             {
359                 return false;
360             }
361         }
362         return true;
363     }
364
365     public String JavaDoc toString()
366     {
367         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
368         sb.append("Mappings:\n");
369         for (Iterator iterator = mappings.keySet().iterator(); iterator.hasNext();)
370         {
371             String JavaDoc key = (String JavaDoc) iterator.next();
372             sb.append(key + "=" + (String JavaDoc) mappings.get(key) + "\n");
373         }
374         sb.append("Complex Paths:\n");
375         for (Iterator iterator = complexPaths.iterator(); iterator.hasNext();)
376         {
377             String JavaDoc path = (String JavaDoc) iterator.next();
378             sb.append(path + "\n");
379         }
380
381         return sb.toString();
382     }
383 }
384
Popular Tags