001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.tools.util;
019:
020: import java.util.ArrayList;
021: import java.util.List;
022:
023: import org.apache.cxf.helpers.JavaUtils;
024:
025: public final class NameUtil {
026:
027: static final int UPPER_LETTER = 0;
028: static final int LOWER_LETTER = 1;
029: static final int OTHER_LETTER = 2;
030: static final int DIGIT = 3;
031: static final int OTHER = 4;
032:
033: private static final byte ACTION_CHECK_PUNCT = 0;
034: private static final byte ACTION_CHECK_C2 = 1;
035: private static final byte ACTION_BREAK = 2;
036: private static final byte ACTION_NOBREAK = 3;
037:
038: private static final byte[] ACTION_TABLE = new byte[5 * 5];
039:
040: private NameUtil() {
041: }
042:
043: static {
044: for (int t0 = 0; t0 < 5; t0++) {
045: for (int t1 = 0; t1 < 5; t1++) {
046: ACTION_TABLE[t0 * 5 + t1] = decideAction(t0, t1);
047: }
048: }
049: }
050:
051: protected static boolean isPunct(char c) {
052: boolean isPunct = c == '-' || c == '.' || c == ':' || c == '_';
053: boolean isUnicodePunct = c == '\u00b7' || c == '\u0387'
054: || c == '\u06dd' || c == '\u06de';
055: return isPunct || isUnicodePunct;
056: }
057:
058: protected static boolean isLower(char c) {
059: return c >= 'a' && c <= 'z' || Character.isLowerCase(c);
060: }
061:
062: public static String capitalize(String s) {
063: if (!isLower(s.charAt(0))) {
064: return s;
065: }
066: StringBuilder sb = new StringBuilder(s.length());
067: sb.append(Character.toUpperCase(s.charAt(0)));
068: sb.append(s.substring(1).toLowerCase());
069: return sb.toString();
070: }
071:
072: private static int nextBreak(String s, int start) {
073: int n = s.length();
074:
075: char c1 = s.charAt(start);
076: int t1 = classify(c1);
077:
078: for (int i = start + 1; i < n; i++) {
079: int t0 = t1;
080:
081: c1 = s.charAt(i);
082: t1 = classify(c1);
083:
084: switch (ACTION_TABLE[t0 * 5 + t1]) {
085: case ACTION_CHECK_PUNCT:
086: if (isPunct(c1)) {
087: return i;
088: }
089: break;
090: case ACTION_CHECK_C2:
091: if (i < n - 1) {
092: char c2 = s.charAt(i + 1);
093: if (isLower(c2)) {
094: return i;
095: }
096: }
097: break;
098: case ACTION_BREAK:
099: return i;
100: default:
101: }
102: }
103: return -1;
104: }
105:
106: private static byte decideAction(int t0, int t1) {
107: if (t0 == OTHER && t1 == OTHER) {
108: return ACTION_CHECK_PUNCT;
109: }
110: if (!xor(t0 == DIGIT, t1 == DIGIT)
111: || (t0 == LOWER_LETTER && t1 != LOWER_LETTER)) {
112: return ACTION_BREAK;
113: }
114: if (!xor(t0 <= OTHER_LETTER, t1 <= OTHER_LETTER)) {
115: return ACTION_BREAK;
116: }
117: if (!xor(t0 == OTHER_LETTER, t1 == OTHER_LETTER)) {
118: return ACTION_BREAK;
119: }
120: if (t0 == UPPER_LETTER && t1 == UPPER_LETTER) {
121: return ACTION_CHECK_C2;
122: }
123:
124: return ACTION_NOBREAK;
125: }
126:
127: private static boolean xor(boolean x, boolean y) {
128: return (x && y) || (!x && !y);
129: }
130:
131: protected static int classify(char c0) {
132: switch (Character.getType(c0)) {
133: case Character.UPPERCASE_LETTER:
134: return UPPER_LETTER;
135: case Character.LOWERCASE_LETTER:
136: return LOWER_LETTER;
137: case Character.TITLECASE_LETTER:
138: case Character.MODIFIER_LETTER:
139: case Character.OTHER_LETTER:
140: return OTHER_LETTER;
141: case Character.DECIMAL_DIGIT_NUMBER:
142: return DIGIT;
143: default:
144: return OTHER;
145: }
146: }
147:
148: public static List<String> toWordList(String s) {
149: List<String> ss = new ArrayList<String>();
150: int n = s.length();
151: for (int i = 0; i < n;) {
152: while (i < n) {
153: if (!isPunct(s.charAt(i))) {
154: break;
155: }
156: i++;
157: }
158: if (i >= n) {
159: break;
160: }
161:
162: int b = nextBreak(s, i);
163: String w = (b == -1) ? s.substring(i) : s.substring(i, b);
164: ss.add(escape(capitalize(w)));
165: if (b == -1) {
166: break;
167: }
168: i = b;
169: }
170:
171: return ss;
172: }
173:
174: protected static String toMixedCaseName(List<String> ss,
175: boolean startUpper) {
176: StringBuilder sb = new StringBuilder();
177: if (!ss.isEmpty()) {
178: sb.append(startUpper ? ss.get(0) : ss.get(0).toLowerCase());
179: for (int i = 1; i < ss.size(); i++) {
180: sb.append(ss.get(i));
181: }
182: }
183: return sb.toString();
184: }
185:
186: protected static String toMixedCaseVariableName(String[] ss,
187: boolean startUpper, boolean cdrUpper) {
188: if (cdrUpper) {
189: for (int i = 1; i < ss.length; i++) {
190: ss[i] = capitalize(ss[i]);
191: }
192: }
193: StringBuilder sb = new StringBuilder();
194: if (ss.length > 0) {
195: sb.append(startUpper ? ss[0] : ss[0].toLowerCase());
196: for (int i = 1; i < ss.length; i++) {
197: sb.append(ss[i]);
198: }
199: }
200: return sb.toString();
201: }
202:
203: public static void escape(StringBuilder sb, String s, int start) {
204: int n = s.length();
205: for (int i = start; i < n; i++) {
206: char c = s.charAt(i);
207: if (Character.isJavaIdentifierPart(c)) {
208: sb.append(c);
209: } else {
210: sb.append('_');
211: if (c <= '\u000f') {
212: sb.append("000");
213: } else if (c <= '\u00ff') {
214: sb.append("00");
215: } else if (c <= '\u0fff') {
216: sb.append('0');
217: }
218: sb.append(Integer.toString(c, 16));
219: }
220: }
221: }
222:
223: private static String escape(String s) {
224: int n = s.length();
225: for (int i = 0; i < n; i++) {
226: if (!Character.isJavaIdentifierPart(s.charAt(i))) {
227: StringBuilder sb = new StringBuilder(s.substring(0, i));
228: escape(sb, s, i);
229: return sb.toString();
230: }
231: }
232: return s;
233: }
234:
235: public static boolean isJavaIdentifier(String s) {
236: if (s.length() == 0) {
237: return false;
238: }
239: if (JavaUtils.isJavaKeyword(s)) {
240: return false;
241: }
242:
243: if (!Character.isJavaIdentifierStart(s.charAt(0))) {
244: return false;
245: }
246:
247: for (int i = 1; i < s.length(); i++) {
248: if (!Character.isJavaIdentifierPart(s.charAt(i))) {
249: return false;
250: }
251: }
252:
253: return true;
254: }
255:
256: public static String mangleNameToClassName(String name) {
257: return toMixedCaseName(toWordList(name), true);
258: }
259:
260: public static String mangleNameToVariableName(String name) {
261: return toMixedCaseName(toWordList(name), false);
262: }
263: }
|