KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tonicsystems > jarjar > Wildcard


1 /*
2   Jar Jar Links - A utility to repackage and embed Java libraries
3   Copyright (C) 2004 Tonic Systems, Inc.
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; see the file COPYING. if not, write to
17   the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18   Boston, MA 02111-1307 USA
19 */

20
21 package com.tonicsystems.jarjar;
22
23 import com.tonicsystems.jarjar.regex.*;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Arrays JavaDoc;
26
27 class Wildcard
28 {
29     private static RegexEngine REGEX = MyRegexEngine.getInstance();
30     
31     public static final int STYLE_DESC = 0;
32     public static final int STYLE_IDENTIFIER = 1;
33
34     private static Pattern dots = REGEX.compile("\\.");
35     private static Pattern tilde = REGEX.compile("~");
36     private static Pattern dstar = REGEX.compile("\\*\\*");
37     private static Pattern star = REGEX.compile("\\*");
38
39     private Pattern descPattern;
40     private Pattern identifierPattern;
41     private int count;
42
43     private ArrayList JavaDoc parts = new ArrayList JavaDoc(16); // kept for debugging
44
private String JavaDoc[] strings;
45     private int[] refs;
46
47     public Wildcard(String JavaDoc pattern, String JavaDoc result) {
48         compilePattern(pattern);
49         compileResult(result);
50         // System.err.println(this);
51
}
52
53     public boolean matches(String JavaDoc value, int style) {
54         return getPattern(style).matches(value);
55     }
56
57     public String JavaDoc replace(String JavaDoc value, int style) {
58         Matcher matcher = getPattern(style).getMatcher(value);
59         if (matcher.matches()) {
60             if (style == STYLE_IDENTIFIER && !checkIdentifierChars(value, false))
61                 return null;
62             return replace(value, style, matcher);
63         }
64         return null;
65     }
66
67     private Pattern getPattern(int style) {
68         switch (style) {
69         case STYLE_DESC:
70             return descPattern;
71         case STYLE_IDENTIFIER:
72             return identifierPattern;
73         default:
74             throw new IllegalArgumentException JavaDoc("Unknown style " + style);
75         }
76     }
77
78     private String JavaDoc replace(String JavaDoc value, int style, Matcher match) {
79         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
80         sb.append(value.substring(0, match.start()));
81         sb.append(match.group(1));
82         for (int i = 0; i < strings.length; i++) {
83             int ref = refs[i];
84             if (ref == 0) {
85                 String JavaDoc s = match.group(0);
86                 s = s.substring(match.group(1).length(),
87                                 s.length() - match.group(count).length());
88                 sb.append(postProcess(s, style));
89             } else if (ref > 0) {
90                 sb.append(postProcess(match.group(ref + 1), style));
91             } else {
92                 sb.append(postProcess(strings[i], style));
93             }
94         }
95         sb.append(match.group(count));
96         sb.append(value.substring(match.end()));
97         return sb.toString();
98     }
99
100     private String JavaDoc postProcess(String JavaDoc value, int style) {
101         if (style == STYLE_IDENTIFIER) {
102             value = value.replace('/', '.');
103         } else {
104             value = value.replace('.', '/');
105         }
106         return value;
107     }
108
109     private void compilePattern(String JavaDoc expr) {
110         if (expr.equals("**"))
111             throw new IllegalArgumentException JavaDoc("'**' is not a valid pattern");
112         if (!checkIdentifierChars(expr, true))
113             throw new IllegalArgumentException JavaDoc("Not a valid package pattern: " + expr);
114         if (expr.indexOf("***") >= 0)
115             throw new IllegalArgumentException JavaDoc("The sequence '***' is invalid in a package pattern");
116
117         String JavaDoc p1 = expr;
118         p1 = dots.replaceAll(p1, "~");
119         p1 = dstar.replaceAll(p1, "(.+?)");
120         p1 = star.replaceAll(p1, "([^/]+?)");
121         if (p1.endsWith("+?)"))
122             p1 = p1.substring(0, p1.length() - 3) + "*)"; // allow trailing * or ** to match nothing
123

124         String JavaDoc p2 = p1;
125         p2 = tilde.replaceAll(p2, "\\.");
126         p1 = tilde.replaceAll(p1, "/");
127         p1 = "(\\[*L)" + p1 + "(;)"; // TODO: optional semicolon?
128

129         p1 = "\\A" + p1 + "\\Z";
130         p2 = "\\A()" + p2 + "()\\Z";
131         // p2 = "\\A()" + p2 + "()\\b\\Z";
132
// p2 = "\\b(L?)" + p2 + "()\\b";
133

134         descPattern = REGEX.compile(p1);
135         identifierPattern = REGEX.compile(p2);
136
137         count = descPattern.groupCount();
138     }
139
140     // TODO: performance
141
private static boolean checkIdentifierChars(String JavaDoc expr, boolean allowStars) {
142         for (int i = 0, len = expr.length(); i < len; i++) {
143             char ch = expr.charAt(i);
144             switch (ch) {
145             case '*':
146                 if (!allowStars)
147                     return false;
148             case '.':
149                 break;
150             default:
151                 if (!Character.isJavaIdentifierPart(ch))
152                     return false;
153             }
154         }
155         return true;
156     }
157
158     private void compileResult(String JavaDoc value) {
159         // TODO: check for illegal characters
160
char[] chars = value.toCharArray();
161         int max = 0;
162         for (int i = 0, mark = 0, state = 0, len = chars.length; i < len + 1; i++) {
163             char ch = (i == len) ? '@' : chars[i];
164             if (state == 0) {
165                 if (ch == '@') {
166                     parts.add(new String JavaDoc(chars, mark, i - mark));
167                     mark = i + 1;
168                     state = 1;
169                 }
170             } else {
171                 switch (ch) {
172                 case '0':
173                 case '1':
174                 case '2':
175                 case '3':
176                 case '4':
177                 case '5':
178                 case '6':
179                 case '7':
180                 case '8':
181                 case '9':
182                     break;
183                 default:
184                     if (i == mark)
185                         throw new IllegalArgumentException JavaDoc("Backslash not followed by a digit");
186                     int n = Integer.parseInt(new String JavaDoc(chars, mark, i - mark));
187                     if (n > max)
188                         max = n;
189                     parts.add(new Integer JavaDoc(n));
190                     mark = i--;
191                     state = 0;
192                 }
193             }
194         }
195         int size = parts.size();
196         strings = new String JavaDoc[size];
197         refs = new int[size];
198         Arrays.fill(refs, -1);
199         for (int i = 0; i < size; i++) {
200             Object JavaDoc v = parts.get(i);
201             if (v instanceof String JavaDoc) {
202                 strings[i] = (String JavaDoc)v;
203             } else {
204                 refs[i] = ((Integer JavaDoc)v).intValue();
205             }
206         }
207         if (count < max)
208             throw new IllegalArgumentException JavaDoc("Result includes impossible placeholder \"@" + max + "\": " + value);
209     }
210
211     public String JavaDoc toString() {
212         return "Wildcard{descPattern=" + descPattern +
213             ",identifierPattern=" + identifierPattern +
214             ",parts=" + parts + "}";
215     }
216 }
217
Popular Tags