KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > kernel > config > SelectorUtils


1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 package org.apache.geronimo.kernel.config;
18
19 import java.io.File JavaDoc;
20 import java.util.StringTokenizer JavaDoc;
21 import java.util.Vector JavaDoc;
22
23 /**
24  * <p>This is a utility class used by selectors and DirectoryScanner. The
25  * functionality more properly belongs just to selectors, but unfortunately
26  * DirectoryScanner exposed these as protected methods. Thus we have to
27  * support any subclasses of DirectoryScanner that may access these methods.
28  * </p>
29  * <p>This is a Singleton.</p>
30  *
31  * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
32  */

33 public final class SelectorUtils {
34     private static SelectorUtils instance = new SelectorUtils();
35
36     private static boolean onNetWare = Os.isFamily("netware");
37     private static boolean onDos = Os.isFamily("dos");
38
39     /**
40      * Private Constructor
41      */

42     private SelectorUtils() {
43     }
44
45     /**
46      * Retrieves the instance of the Singleton.
47      * @return singleton instance
48      */

49     public static SelectorUtils getInstance() {
50         return instance;
51     }
52
53     /**
54      * Tests whether or not a given path matches the start of a given
55      * pattern up to the first "**".
56      * <p>
57      * This is not a general purpose test and should only be used if you
58      * can live with false positives. For example, <code>pattern=**\a</code>
59      * and <code>str=b</code> will yield <code>true</code>.
60      *
61      * @param pattern The pattern to match against. Must not be
62      * <code>null</code>.
63      * @param str The path to match, as a String. Must not be
64      * <code>null</code>.
65      *
66      * @return whether or not a given path matches the start of a given
67      * pattern up to the first "**".
68      */

69     public static boolean matchPatternStart(String JavaDoc pattern, String JavaDoc str) {
70         return matchPatternStart(pattern, str, true);
71     }
72
73     /**
74      * Tests whether or not a given path matches the start of a given
75      * pattern up to the first "**".
76      * <p>
77      * This is not a general purpose test and should only be used if you
78      * can live with false positives. For example, <code>pattern=**\a</code>
79      * and <code>str=b</code> will yield <code>true</code>.
80      *
81      * @param pattern The pattern to match against. Must not be
82      * <code>null</code>.
83      * @param str The path to match, as a String. Must not be
84      * <code>null</code>.
85      * @param isCaseSensitive Whether or not matching should be performed
86      * case sensitively.
87      *
88      * @return whether or not a given path matches the start of a given
89      * pattern up to the first "**".
90      */

91     public static boolean matchPatternStart(String JavaDoc pattern, String JavaDoc str,
92                                             boolean isCaseSensitive) {
93         // When str starts with a File.separator, pattern has to start with a
94
// File.separator.
95
// When pattern starts with a File.separator, str has to start with a
96
// File.separator.
97
if (str.startsWith(File.separator)
98                 != pattern.startsWith(File.separator)) {
99             return false;
100         }
101
102         String JavaDoc[] patDirs = tokenizePathAsArray(pattern);
103         String JavaDoc[] strDirs = tokenizePathAsArray(str);
104
105         int patIdxStart = 0;
106         int patIdxEnd = patDirs.length - 1;
107         int strIdxStart = 0;
108         int strIdxEnd = strDirs.length - 1;
109
110         // up to first '**'
111
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
112             String JavaDoc patDir = patDirs[patIdxStart];
113             if (patDir.equals("**")) {
114                 break;
115             }
116             if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
117                 return false;
118             }
119             patIdxStart++;
120             strIdxStart++;
121         }
122
123         if (strIdxStart > strIdxEnd) {
124             // String is exhausted
125
return true;
126         } else if (patIdxStart > patIdxEnd) {
127             // String not exhausted, but pattern is. Failure.
128
return false;
129         } else {
130             // pattern now holds ** while string is not exhausted
131
// this will generate false positives but we can live with that.
132
return true;
133         }
134     }
135
136     /**
137      * Tests whether or not a given path matches a given pattern.
138      *
139      * @param pattern The pattern to match against. Must not be
140      * <code>null</code>.
141      * @param str The path to match, as a String. Must not be
142      * <code>null</code>.
143      *
144      * @return <code>true</code> if the pattern matches against the string,
145      * or <code>false</code> otherwise.
146      */

147     public static boolean matchPath(String JavaDoc pattern, String JavaDoc str) {
148         return matchPath(pattern, str, true);
149     }
150
151     /**
152      * Tests whether or not a given path matches a given pattern.
153      *
154      * @param pattern The pattern to match against. Must not be
155      * <code>null</code>.
156      * @param str The path to match, as a String. Must not be
157      * <code>null</code>.
158      * @param isCaseSensitive Whether or not matching should be performed
159      * case sensitively.
160      *
161      * @return <code>true</code> if the pattern matches against the string,
162      * or <code>false</code> otherwise.
163      */

164     public static boolean matchPath(String JavaDoc pattern, String JavaDoc str,
165                                     boolean isCaseSensitive) {
166         String JavaDoc[] patDirs = tokenizePathAsArray(pattern);
167         String JavaDoc[] strDirs = tokenizePathAsArray(str);
168
169         int patIdxStart = 0;
170         int patIdxEnd = patDirs.length - 1;
171         int strIdxStart = 0;
172         int strIdxEnd = strDirs.length - 1;
173
174         // up to first '**'
175
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
176             String JavaDoc patDir = patDirs[patIdxStart];
177             if (patDir.equals("**")) {
178                 break;
179             }
180             if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
181                 patDirs = null;
182                 strDirs = null;
183                 return false;
184             }
185             patIdxStart++;
186             strIdxStart++;
187         }
188         if (strIdxStart > strIdxEnd) {
189             // String is exhausted
190
for (int i = patIdxStart; i <= patIdxEnd; i++) {
191                 if (!patDirs[i].equals("**")) {
192                     patDirs = null;
193                     strDirs = null;
194                     return false;
195                 }
196             }
197             return true;
198         } else {
199             if (patIdxStart > patIdxEnd) {
200                 // String not exhausted, but pattern is. Failure.
201
patDirs = null;
202                 strDirs = null;
203                 return false;
204             }
205         }
206
207         // up to last '**'
208
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
209             String JavaDoc patDir = patDirs[patIdxEnd];
210             if (patDir.equals("**")) {
211                 break;
212             }
213             if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) {
214                 patDirs = null;
215                 strDirs = null;
216                 return false;
217             }
218             patIdxEnd--;
219             strIdxEnd--;
220         }
221         if (strIdxStart > strIdxEnd) {
222             // String is exhausted
223
for (int i = patIdxStart; i <= patIdxEnd; i++) {
224                 if (!patDirs[i].equals("**")) {
225                     patDirs = null;
226                     strDirs = null;
227                     return false;
228                 }
229             }
230             return true;
231         }
232
233         while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
234             int patIdxTmp = -1;
235             for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
236                 if (patDirs[i].equals("**")) {
237                     patIdxTmp = i;
238                     break;
239                 }
240             }
241             if (patIdxTmp == patIdxStart + 1) {
242                 // '**/**' situation, so skip one
243
patIdxStart++;
244                 continue;
245             }
246             // Find the pattern between padIdxStart & padIdxTmp in str between
247
// strIdxStart & strIdxEnd
248
int patLength = (patIdxTmp - patIdxStart - 1);
249             int strLength = (strIdxEnd - strIdxStart + 1);
250             int foundIdx = -1;
251             strLoop:
252                         for (int i = 0; i <= strLength - patLength; i++) {
253                             for (int j = 0; j < patLength; j++) {
254                                 String JavaDoc subPat = patDirs[patIdxStart + j + 1];
255                                 String JavaDoc subStr = strDirs[strIdxStart + i + j];
256                                 if (!match(subPat, subStr, isCaseSensitive)) {
257                                     continue strLoop;
258                                 }
259                             }
260
261                             foundIdx = strIdxStart + i;
262                             break;
263                         }
264
265             if (foundIdx == -1) {
266                 patDirs = null;
267                 strDirs = null;
268                 return false;
269             }
270
271             patIdxStart = patIdxTmp;
272             strIdxStart = foundIdx + patLength;
273         }
274
275         for (int i = patIdxStart; i <= patIdxEnd; i++) {
276             if (!patDirs[i].equals("**")) {
277                 patDirs = null;
278                 strDirs = null;
279                 return false;
280             }
281         }
282
283         return true;
284     }
285
286     /**
287      * Tests whether or not a string matches against a pattern.
288      * The pattern may contain two special characters:<br>
289      * '*' means zero or more characters<br>
290      * '?' means one and only one character
291      *
292      * @param pattern The pattern to match against.
293      * Must not be <code>null</code>.
294      * @param str The string which must be matched against the pattern.
295      * Must not be <code>null</code>.
296      *
297      * @return <code>true</code> if the string matches against the pattern,
298      * or <code>false</code> otherwise.
299      */

300     public static boolean match(String JavaDoc pattern, String JavaDoc str) {
301         return match(pattern, str, true);
302     }
303
304     /**
305      * Tests whether or not a string matches against a pattern.
306      * The pattern may contain two special characters:<br>
307      * '*' means zero or more characters<br>
308      * '?' means one and only one character
309      *
310      * @param pattern The pattern to match against.
311      * Must not be <code>null</code>.
312      * @param str The string which must be matched against the pattern.
313      * Must not be <code>null</code>.
314      * @param isCaseSensitive Whether or not matching should be performed
315      * case sensitively.
316      *
317      *
318      * @return <code>true</code> if the string matches against the pattern,
319      * or <code>false</code> otherwise.
320      */

321     public static boolean match(String JavaDoc pattern, String JavaDoc str,
322                                 boolean isCaseSensitive) {
323         char[] patArr = pattern.toCharArray();
324         char[] strArr = str.toCharArray();
325         int patIdxStart = 0;
326         int patIdxEnd = patArr.length - 1;
327         int strIdxStart = 0;
328         int strIdxEnd = strArr.length - 1;
329         char ch;
330
331         boolean containsStar = false;
332         for (int i = 0; i < patArr.length; i++) {
333             if (patArr[i] == '*') {
334                 containsStar = true;
335                 break;
336             }
337         }
338
339         if (!containsStar) {
340             // No '*'s, so we make a shortcut
341
if (patIdxEnd != strIdxEnd) {
342                 return false; // Pattern and string do not have the same size
343
}
344             for (int i = 0; i <= patIdxEnd; i++) {
345                 ch = patArr[i];
346                 if (ch != '?') {
347                     if (isCaseSensitive && ch != strArr[i]) {
348                         return false; // Character mismatch
349
}
350                     if (!isCaseSensitive && Character.toUpperCase(ch)
351                             != Character.toUpperCase(strArr[i])) {
352                         return false; // Character mismatch
353
}
354                 }
355             }
356             return true; // String matches against pattern
357
}
358
359         if (patIdxEnd == 0) {
360             return true; // Pattern contains only '*', which matches anything
361
}
362
363         // Process characters before first star
364
while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
365             if (ch != '?') {
366                 if (isCaseSensitive && ch != strArr[strIdxStart]) {
367                     return false; // Character mismatch
368
}
369                 if (!isCaseSensitive && Character.toUpperCase(ch)
370                         != Character.toUpperCase(strArr[strIdxStart])) {
371                     return false; // Character mismatch
372
}
373             }
374             patIdxStart++;
375             strIdxStart++;
376         }
377         if (strIdxStart > strIdxEnd) {
378             // All characters in the string are used. Check if only '*'s are
379
// left in the pattern. If so, we succeeded. Otherwise failure.
380
for (int i = patIdxStart; i <= patIdxEnd; i++) {
381                 if (patArr[i] != '*') {
382                     return false;
383                 }
384             }
385             return true;
386         }
387
388         // Process characters after last star
389
while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
390             if (ch != '?') {
391                 if (isCaseSensitive && ch != strArr[strIdxEnd]) {
392                     return false; // Character mismatch
393
}
394                 if (!isCaseSensitive && Character.toUpperCase(ch)
395                         != Character.toUpperCase(strArr[strIdxEnd])) {
396                     return false; // Character mismatch
397
}
398             }
399             patIdxEnd--;
400             strIdxEnd--;
401         }
402         if (strIdxStart > strIdxEnd) {
403             // All characters in the string are used. Check if only '*'s are
404
// left in the pattern. If so, we succeeded. Otherwise failure.
405
for (int i = patIdxStart; i <= patIdxEnd; i++) {
406                 if (patArr[i] != '*') {
407                     return false;
408                 }
409             }
410             return true;
411         }
412
413         // process pattern between stars. padIdxStart and patIdxEnd point
414
// always to a '*'.
415
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
416             int patIdxTmp = -1;
417             for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
418                 if (patArr[i] == '*') {
419                     patIdxTmp = i;
420                     break;
421                 }
422             }
423             if (patIdxTmp == patIdxStart + 1) {
424                 // Two stars next to each other, skip the first one.
425
patIdxStart++;
426                 continue;
427             }
428             // Find the pattern between padIdxStart & padIdxTmp in str between
429
// strIdxStart & strIdxEnd
430
int patLength = (patIdxTmp - patIdxStart - 1);
431             int strLength = (strIdxEnd - strIdxStart + 1);
432             int foundIdx = -1;
433             strLoop:
434             for (int i = 0; i <= strLength - patLength; i++) {
435                 for (int j = 0; j < patLength; j++) {
436                     ch = patArr[patIdxStart + j + 1];
437                     if (ch != '?') {
438                         if (isCaseSensitive && ch != strArr[strIdxStart + i
439                                 + j]) {
440                             continue strLoop;
441                         }
442                         if (!isCaseSensitive
443                             && Character.toUpperCase(ch)
444                                 != Character.toUpperCase(strArr[strIdxStart + i + j])) {
445                             continue strLoop;
446                         }
447                     }
448                 }
449
450                 foundIdx = strIdxStart + i;
451                 break;
452             }
453
454             if (foundIdx == -1) {
455                 return false;
456             }
457
458             patIdxStart = patIdxTmp;
459             strIdxStart = foundIdx + patLength;
460         }
461
462         // All characters in the string are used. Check if only '*'s are left
463
// in the pattern. If so, we succeeded. Otherwise failure.
464
for (int i = patIdxStart; i <= patIdxEnd; i++) {
465             if (patArr[i] != '*') {
466                 return false;
467             }
468         }
469         return true;
470     }
471
472     /**
473      * Breaks a path up into a Vector of path elements, tokenizing on
474      * <code>File.separator</code>.
475      *
476      * @param path Path to tokenize. Must not be <code>null</code>.
477      *
478      * @return a Vector of path elements from the tokenized path
479      */

480     public static Vector JavaDoc tokenizePath (String JavaDoc path) {
481         return tokenizePath(path, File.separator);
482     }
483
484     /**
485      * Verifies that the specified filename represents an absolute path.
486      * Differs from new java.io.File("filename").isAbsolute() in that a path
487      * beginning with a double file separator--signifying a Windows UNC--must
488      * at minimum match "\\a\b" to be considered an absolute path.
489      * @param filename the filename to be checked.
490      * @return true if the filename represents an absolute path.
491      * @throws java.lang.NullPointerException if filename is null.
492      * @since Ant 1.6.3
493      */

494     public static boolean isAbsolutePath(String JavaDoc filename) {
495         int len = filename.length();
496         if (len == 0) {
497             return false;
498         }
499         char sep = File.separatorChar;
500         filename = filename.replace('/', sep).replace('\\', sep);
501         char c = filename.charAt(0);
502         if (!(onDos || onNetWare)) {
503             return (c == sep);
504         }
505         if (c == sep) {
506             if (!(onDos && len > 4 && filename.charAt(1) == sep)) {
507                 return false;
508             }
509             int nextsep = filename.indexOf(sep, 2);
510             return nextsep > 2 && nextsep + 1 < len;
511         }
512         int colon = filename.indexOf(':');
513         return (Character.isLetter(c) && colon == 1
514             && filename.length() > 2 && filename.charAt(2) == sep)
515             || (onNetWare && colon > 0);
516     }
517
518     /**
519      * Dissect the specified absolute path.
520      * @param path the path to dissect.
521      * @return String[] {root, remaining path}.
522      * @throws java.lang.NullPointerException if path is null.
523      */

524     public static String JavaDoc[] dissect(String JavaDoc path) {
525         char sep = File.separatorChar;
526         path = path.replace('/', sep).replace('\\', sep);
527
528         // make sure we are dealing with an absolute path
529
if (!isAbsolutePath(path)) {
530             throw new IllegalArgumentException JavaDoc(path + " is not an absolute path");
531         }
532         String JavaDoc root = null;
533         int colon = path.indexOf(':');
534         if (colon > 0 && (onDos || onNetWare)) {
535
536             int next = colon + 1;
537             root = path.substring(0, next).toUpperCase();
538             char[] ca = path.toCharArray();
539             root += sep;
540             //remove the initial separator; the root has it.
541
next = (ca[next] == sep) ? next + 1 : next;
542
543             StringBuffer JavaDoc sbPath = new StringBuffer JavaDoc();
544             // Eliminate consecutive slashes after the drive spec:
545
for (int i = next; i < ca.length; i++) {
546                 if (ca[i] != sep || ca[i - 1] != sep) {
547                     sbPath.append(ca[i]);
548                 }
549             }
550             path = sbPath.toString();
551         } else if (path.length() > 1 && path.charAt(1) == sep) {
552             // UNC drive
553
int nextsep = path.indexOf(sep, 2);
554             nextsep = path.indexOf(sep, nextsep + 1);
555             root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path;
556             path = path.substring(root.length());
557         } else {
558             root = File.separator;
559             path = path.substring(1);
560         }
561         return new String JavaDoc[] {root, path};
562     }
563
564
565     /**
566      * Breaks a path up into a Vector of path elements, tokenizing on
567      *
568      * @param path Path to tokenize. Must not be <code>null</code>.
569      * @param separator the separator against which to tokenize.
570      *
571      * @return a Vector of path elements from the tokenized path
572      * @since Ant 1.6
573      */

574     public static Vector JavaDoc tokenizePath (String JavaDoc path, String JavaDoc separator) {
575         Vector JavaDoc ret = new Vector JavaDoc();
576         if (isAbsolutePath(path)) {
577             String JavaDoc[] s = dissect(path);
578             ret.add(s[0]);
579             path = s[1];
580         }
581         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(path, separator);
582         while (st.hasMoreTokens()) {
583             ret.addElement(st.nextToken());
584         }
585         return ret;
586     }
587
588     /**
589      * Same as {@link #tokenizePath tokenizePath} but hopefully faster.
590      */

591     private static String JavaDoc[] tokenizePathAsArray(String JavaDoc path) {
592         String JavaDoc root = null;
593         if (isAbsolutePath(path)) {
594             String JavaDoc[] s = dissect(path);
595             root = s[0];
596             path = s[1];
597         }
598         char sep = File.separatorChar;
599         int start = 0;
600         int len = path.length();
601         int count = 0;
602         for (int pos = 0; pos < len; pos++) {
603             if (path.charAt(pos) == sep) {
604                 if (pos != start) {
605                     count++;
606                 }
607                 start = pos + 1;
608             }
609         }
610         if (len != start) {
611             count++;
612         }
613         String JavaDoc[] l = new String JavaDoc[count + ((root == null) ? 0 : 1)];
614
615         if (root != null) {
616             l[0] = root;
617             count = 1;
618         } else {
619             count = 0;
620         }
621         start = 0;
622         for (int pos = 0; pos < len; pos++) {
623             if (path.charAt(pos) == sep) {
624                 if (pos != start) {
625                     String JavaDoc tok = path.substring(start, pos);
626                     l[count++] = tok;
627                 }
628                 start = pos + 1;
629             }
630         }
631         if (len != start) {
632             String JavaDoc tok = path.substring(start);
633             l[count/*++*/] = tok;
634         }
635         return l;
636     }
637
638
639     /**
640      * Returns dependency information on these two files. If src has been
641      * modified later than target, it returns true. If target doesn't exist,
642      * it likewise returns true. Otherwise, target is newer than src and
643      * is not out of date, thus the method returns false. It also returns
644      * false if the src file doesn't even exist, since how could the
645      * target then be out of date.
646      *
647      * @param src the original file
648      * @param target the file being compared against
649      * @param granularity the amount in seconds of slack we will give in
650      * determining out of dateness
651      * @return whether the target is out of date
652      */

653     public static boolean isOutOfDate(File JavaDoc src, File JavaDoc target, int granularity) {
654         if (!src.exists()) {
655             return false;
656         }
657         if (!target.exists()) {
658             return true;
659         }
660         if ((src.lastModified() - granularity) > target.lastModified()) {
661             return true;
662         }
663         return false;
664     }
665
666     /**
667      * "Flattens" a string by removing all whitespace (space, tab, linefeed,
668      * carriage return, and formfeed). This uses StringTokenizer and the
669      * default set of tokens as documented in the single arguement constructor.
670      *
671      * @param input a String to remove all whitespace.
672      * @return a String that has had all whitespace removed.
673      */

674     public static String JavaDoc removeWhitespace(String JavaDoc input) {
675         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
676         if (input != null) {
677             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(input);
678             while (st.hasMoreTokens()) {
679                 result.append(st.nextToken());
680             }
681         }
682         return result.toString();
683     }
684
685     /**
686      * Tests if a string contains stars or question marks
687      * @param input a String which one wants to test for containing wildcard
688      * @return true if the string contains at least a star or a question mark
689      */

690     public static boolean hasWildcards(String JavaDoc input) {
691         return (input.indexOf('*') != -1 || input.indexOf('?') != -1);
692     }
693
694     /**
695      * removes from a pattern all tokens to the right containing wildcards
696      * @param input the input string
697      * @return the leftmost part of the pattern without wildcards
698      */

699     public static String JavaDoc rtrimWildcardTokens(String JavaDoc input) {
700         Vector JavaDoc v = tokenizePath(input, File.separator);
701         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
702         for (int counter = 0; counter < v.size(); counter++) {
703             if (hasWildcards((String JavaDoc) v.elementAt(counter))) {
704                 break;
705             }
706             if (counter > 0 && sb.charAt(sb.length() - 1) != File.separatorChar) {
707                 sb.append(File.separator);
708             }
709             sb.append((String JavaDoc) v.elementAt(counter));
710         }
711         return sb.toString();
712     }
713 }
714
715
Popular Tags