001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.internal.txw2;
027:
028: import com.sun.codemodel.JJavaName;
029:
030: import java.util.ArrayList;
031:
032: /**
033: * @author Kohsuke Kawaguchi
034: */
035: public class NameUtil {
036:
037: protected static boolean isPunct(char c) {
038: return (c == '-' || c == '.' || c == ':' || c == '_'
039: || c == '\u00b7' || c == '\u0387' || c == '\u06dd' || c == '\u06de');
040: }
041:
042: protected static boolean isDigit(char c) {
043: return ((c >= '0' && c <= '9') || Character.isDigit(c));
044: }
045:
046: protected static boolean isUpper(char c) {
047: return ((c >= 'A' && c <= 'Z') || Character.isUpperCase(c));
048: }
049:
050: protected static boolean isLower(char c) {
051: return ((c >= 'a' && c <= 'z') || Character.isLowerCase(c));
052: }
053:
054: protected static boolean isLetter(char c) {
055: return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || Character
056: .isLetter(c));
057: }
058:
059: /**
060: * Capitalizes the first character of the specified string,
061: * and de-capitalize the rest of characters.
062: */
063: public static String capitalize(String s) {
064: if (!isLower(s.charAt(0)))
065: return s;
066: StringBuffer sb = new StringBuffer(s.length());
067: sb.append(Character.toUpperCase(s.charAt(0)));
068: sb.append(s.substring(1).toLowerCase());
069: return sb.toString();
070: }
071:
072: // Precondition: s[start] is not punctuation
073: protected static int nextBreak(String s, int start) {
074: int n = s.length();
075: for (int i = start; i < n; i++) {
076: char c0 = s.charAt(i);
077: if (i < n - 1) {
078: char c1 = s.charAt(i + 1);
079: if (isPunct(c1))
080: return i + 1;
081: if (isDigit(c0) && !isDigit(c1))
082: return i + 1;
083: if (!isDigit(c0) && isDigit(c1))
084: return i + 1;
085: if (isLower(c0) && !isLower(c1))
086: return i + 1;
087: if (isLetter(c0) && !isLetter(c1))
088: return i + 1;
089: if (!isLetter(c0) && isLetter(c1))
090: return i + 1;
091: if (i < n - 2) {
092: char c2 = s.charAt(i + 2);
093: if (isUpper(c0) && isUpper(c1) && isLower(c2))
094: return i + 1;
095: }
096: }
097: }
098: return -1;
099: }
100:
101: /**
102: * Tokenizes a string into words and capitalizes the first
103: * character of each word.
104: *
105: * <p>
106: * This method uses a change in character type as a splitter
107: * of two words. For example, "abc100ghi" will be splitted into
108: * {"Abc", "100","Ghi"}.
109: */
110: public static String[] toWordList(String s) {
111: ArrayList ss = new ArrayList();
112: int n = s.length();
113: for (int i = 0; i < n;) {
114:
115: // Skip punctuation
116: while (i < n) {
117: if (!isPunct(s.charAt(i)))
118: break;
119: i++;
120: }
121: if (i >= n)
122: break;
123:
124: // Find next break and collect word
125: int b = nextBreak(s, i);
126: String w = (b == -1) ? s.substring(i) : s.substring(i, b);
127: ss.add(escape(capitalize(w)));
128: if (b == -1)
129: break;
130: i = b;
131: }
132:
133: // we can't guarantee a valid Java identifier anyway,
134: // so there's not much point in rejecting things in this way.
135: // if (ss.size() == 0)
136: // throw new IllegalArgumentException("Zero-length identifier");
137: return (String[]) (ss.toArray(new String[0]));
138: }
139:
140: protected static String toMixedCaseName(String[] ss,
141: boolean startUpper) {
142: StringBuffer sb = new StringBuffer();
143: if (ss.length > 0) {
144: sb.append(startUpper ? ss[0] : ss[0].toLowerCase());
145: for (int i = 1; i < ss.length; i++)
146: sb.append(ss[i]);
147: }
148: return sb.toString();
149: }
150:
151: protected static String toMixedCaseVariableName(String[] ss,
152: boolean startUpper, boolean cdrUpper) {
153: if (cdrUpper)
154: for (int i = 1; i < ss.length; i++)
155: ss[i] = capitalize(ss[i]);
156: StringBuffer sb = new StringBuffer();
157: if (ss.length > 0) {
158: sb.append(startUpper ? ss[0] : ss[0].toLowerCase());
159: for (int i = 1; i < ss.length; i++)
160: sb.append(ss[i]);
161: }
162: return sb.toString();
163: }
164:
165: /**
166: * Formats a string into "THIS_KIND_OF_FORMAT_ABC_DEF".
167: *
168: * @return
169: * Always return a string but there's no guarantee that
170: * the generated code is a valid Java identifier.
171: */
172: public static String toConstantName(String s) {
173: return toConstantName(toWordList(s));
174: }
175:
176: /**
177: * Formats a string into "THIS_KIND_OF_FORMAT_ABC_DEF".
178: *
179: * @return
180: * Always return a string but there's no guarantee that
181: * the generated code is a valid Java identifier.
182: */
183: public static String toConstantName(String[] ss) {
184: StringBuffer sb = new StringBuffer();
185: if (ss.length > 0) {
186: sb.append(ss[0].toUpperCase());
187: for (int i = 1; i < ss.length; i++) {
188: sb.append('_');
189: sb.append(ss[i].toUpperCase());
190: }
191: }
192: return sb.toString();
193: }
194:
195: /**
196: * Escapes characters is the given string so that they can be
197: * printed by only using US-ASCII characters.
198: *
199: * The escaped characters will be appended to the given
200: * StringBuffer.
201: *
202: * @param sb
203: * StringBuffer that receives escaped string.
204: * @param s
205: * String to be escaped. <code>s.substring(start)</code>
206: * will be escaped and copied to the string buffer.
207: */
208: public static void escape(StringBuffer sb, String s, int start) {
209: int n = s.length();
210: for (int i = start; i < n; i++) {
211: char c = s.charAt(i);
212: if (Character.isJavaIdentifierPart(c))
213: sb.append(c);
214: else {
215: sb.append("_");
216: if (c <= '\u000f')
217: sb.append("000");
218: else if (c <= '\u00ff')
219: sb.append("00");
220: else if (c <= '\u0fff')
221: sb.append("0");
222: sb.append(Integer.toString(c, 16));
223: }
224: }
225: }
226:
227: /**
228: * Escapes characters that are unusable as Java identifiers
229: * by replacing unsafe characters with safe characters.
230: */
231: private static String escape(String s) {
232: int n = s.length();
233: for (int i = 0; i < n; i++)
234: if (!Character.isJavaIdentifierPart(s.charAt(i))) {
235: StringBuffer sb = new StringBuffer(s.substring(0, i));
236: escape(sb, s, i);
237: return sb.toString();
238: }
239: return s;
240: }
241:
242: /**
243: * Escape any characters that would cause the single arg constructor
244: * of java.net.URI to complain about illegal chars.
245: *
246: * @param s source string to be escaped
247: */
248: public static String escapeURI(String s) {
249: StringBuffer sb = new StringBuffer();
250: for (int i = 0; i < s.length(); i++) {
251: char c = s.charAt(i);
252: if (Character.isSpaceChar(c)) {
253: sb.append("%20");
254: } else {
255: sb.append(c);
256: }
257: }
258: return sb.toString();
259: }
260:
261: /**
262: * Calculate the parent URI path of the given URI path.
263: *
264: * @param uriPath the uriPath (as returned by java.net.URI#getPath()
265: * @return the parent URI path of the given URI path
266: */
267: public static String getParentUriPath(String uriPath) {
268: int idx = uriPath.lastIndexOf('/');
269:
270: if (uriPath.endsWith("/")) {
271: uriPath = uriPath.substring(0, idx); // trim trailing slash
272: idx = uriPath.lastIndexOf('/'); // move idx to parent context
273: }
274:
275: return uriPath.substring(0, idx) + "/";
276: }
277:
278: /**
279: * Calculate the normalized form of the given uriPath.
280: *
281: * For example:
282: * /a/b/c/ -> /a/b/c/
283: * /a/b/c -> /a/b/
284: * /a/ -> /a/
285: * /a -> /
286: *
287: * @param uriPath path of a URI (as returned by java.net.URI#getPath()
288: * @return the normalized uri path
289: */
290: public static String normalizeUriPath(String uriPath) {
291: if (uriPath.endsWith("/"))
292: return uriPath;
293:
294: // the uri path should always have at least a leading slash,
295: // so no need to make sure that ( idx == -1 )
296: int idx = uriPath.lastIndexOf('/');
297: return uriPath.substring(0, idx + 1);
298: }
299:
300: /**
301: * determine if two Strings are equal ignoring case allowing null values
302: *
303: * @param s string 1
304: * @param t string 2
305: * @return true iff the given strings are equal ignoring case, false if they aren't
306: * equal or either of them are null.
307: */
308: public static boolean equalsIgnoreCase(String s, String t) {
309: if (s == t)
310: return true;
311: if ((s != null) && (t != null)) {
312: return s.equalsIgnoreCase(t);
313: }
314: return false;
315: }
316:
317: /**
318: * determine if two Strings are iqual allowing null values
319: *
320: * @param s string 1
321: * @param t string 2
322: * @return true iff the strings are equal, false if they aren't equal or either of
323: * them are null.
324: */
325: public static boolean equal(String s, String t) {
326: if (s == t)
327: return true;
328: if ((s != null) && (t != null)) {
329: return s.equals(t);
330: }
331: return false;
332: }
333:
334: public static String toClassName(String s) {
335: return toMixedCaseName(toWordList(s), true);
336: }
337:
338: public static String toVariableName(String s) {
339: return toMixedCaseName(toWordList(s), false);
340: }
341:
342: public static String toMethodName(String s) {
343: String m = toMixedCaseName(toWordList(s), false);
344: if (JJavaName.isJavaIdentifier(m))
345: return m;
346: else
347: return '_' + m;
348: }
349:
350: public static String toInterfaceName(String token) {
351: return toClassName(token);
352: }
353:
354: public static String toPropertyName(String s) {
355: return toClassName(s);
356: }
357:
358: public static String toPackageName(String s) {
359: return toMixedCaseName(toWordList(s), false);
360: }
361: }
|