001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.insync.beans;
042:
043: import java.beans.ParameterDescriptor;
044: import java.util.HashSet;
045: import java.util.Set;
046: import java.beans.Introspector;
047:
048: /**
049: * Public utility methods for JavaBean name pattern handling
050: */
051: public class Naming {
052:
053: /**
054: * Return an identifier string with the first letter made lowercase
055: *
056: * @param ident
057: * @return The identifier string with the first letter made lowercase
058: */
059: public static final String firstLowered(String ident) {
060: return Character.toLowerCase(ident.charAt(0))
061: + ident.substring(1, ident.length());
062: }
063:
064: /**
065: * Turn a fully qualified type name into a usable variable name
066: *
067: * @param type Fully qualified type name
068: * @return The last part of a dotted type string sequence made initial lowercase
069: */
070: public static final String varName(String type) {
071: int dot = type.lastIndexOf('.');
072: if (dot >= 0)
073: type = type.substring(dot + 1);
074: return makeValidJavaBeanName(type);
075: }
076:
077: /**
078: * Convert an array of Classes, and possibly assisted by an array of ParameterDescriptors, into
079: * a simple array of string parameter names.
080: *
081: * @param classes Required list of parameter type classes
082: * @param pds Optional javabean parameter descriptors to use if available
083: * @return A string array containing usable parameter names
084: */
085: public static final String[] paramNames(Class[] classes,
086: ParameterDescriptor[] pds) {
087: String[] names = new String[classes.length];
088: if (pds != null) {
089: for (int i = 0; i < classes.length; i++)
090: names[i] = pds[i].getName();
091: } else {
092: String[] types = new String[classes.length];
093: for (int i = 0; i < classes.length; i++) {
094: String type = classes[i].getName();
095: int dot = type.lastIndexOf('.');
096: if (dot >= 0)
097: type = type.substring(dot + 1);
098: types[i] = type;
099: }
100: for (int i = 0; i < classes.length; i++) {
101: boolean unique = true;
102: for (int j = 0; j < types.length; j++) {
103: if (j != i && types[j].equals(types[i])) {
104: unique = false;
105: break;
106: }
107: }
108: StringBuffer nameb = new StringBuffer();
109: for (int j = 0; j < types[i].length(); j++) {
110: char c = types[i].charAt(j);
111: if (Character.isUpperCase(c))
112: nameb.append(Character.toLowerCase(c));
113: }
114: if (!unique)
115: nameb.append(i);
116: String name = nameb.toString();
117: if (isJavaKeyWord(name))
118: names[i] = mangle(name, i);
119: else
120: names[i] = name;
121: }
122: }
123: return names;
124: }
125:
126: /* JavaBeans introspector interprets getter "getFooBah" corresponding to
127: * property "fooBah" but getter "getURL" as corresponding to property "URL".
128: *
129: * Examples where we can have problems
130: * ( Type --> property name --> Getter --> JavaBeans interpretation of property name)
131: * 1) USWeather --> uSWeather --> getUSWeather --> USWeather
132: * 2) eBay --> eBay --> getEBay --> EBay
133: *
134: * Therefore the first two letters are made lower case unless both of them
135: * are upper case
136: *
137: * Also, if the name is a single character, it should be lower case.
138: * For example if the getter is getA(), property name is ambiguous('a' or 'A').
139: *
140: */
141: public static String makeValidJavaBeanName(String name) {
142: char chars[] = name.toCharArray();
143: if (name.length() > 1
144: && !(Character.isUpperCase(chars[0]) && Character
145: .isUpperCase(chars[1]))) {
146: chars[0] = Character.toLowerCase(chars[0]);
147: chars[1] = Character.toLowerCase(chars[1]);
148: } else if (name.length() == 1
149: && Character.isUpperCase(chars[0])) {
150: chars[0] = Character.toLowerCase(chars[0]);
151: }
152: return new String(chars);
153: }
154:
155: /**
156: * @param ident Identifier to capitalize
157: * @return The identifier string with the first character capitalized
158: */
159: public static final String firstUppered(String ident) {
160: return Character.toUpperCase(ident.charAt(0))
161: + ident.substring(1, ident.length());
162: }
163:
164: /**
165: * @param name Property name to create the getter method name for.
166: * @return The getter method name.
167: */
168: public static final String getterName(String name) {
169: return "get" + firstUppered(name);
170: }
171:
172: /**
173: * @param name Property name to create the setter method name for.
174: * @return The setter method name
175: */
176: public static final String setterName(String name) {
177: return "set" + firstUppered(name);
178: }
179:
180: /**
181: * @param name Event name to create the adder method name for.
182: * @return The adder method name
183: */
184: public static final String adderName(String name) {
185: return "add" + firstUppered(name) + "Listener";
186: }
187:
188: /**
189: * @param ident The identifier to check
190: * @return true iff the given string is a valid java identifier
191: */
192: public static final boolean isValidIdentifier(String ident) {
193: if (ident != null && ident.length() > 0
194: && Character.isJavaIdentifierStart(ident.charAt(0))) {
195: for (int i = 1; i < ident.length(); i++) {
196: if (!Character.isJavaIdentifierPart(ident.charAt(i)))
197: return false;
198: }
199: return true;
200: }
201: return false;
202: }
203:
204: /**
205: * Convert a string into a valid java identifier if possible
206: *
207: * @return the fixed up string, or null if unfixable
208: */
209: public static final String makeValidIdentifier(String ident) {
210: if (ident == null || ident.length() == 0)
211: return null;
212:
213: StringBuffer sb = new StringBuffer(ident);
214: // trim leading bad identifier chars (including whitespace)
215: while (sb.length() > 0
216: && !Character.isJavaIdentifierStart(sb.charAt(0)))
217: sb.deleteCharAt(0);
218:
219: // trim trailing bad identifier chars (including whitespace)
220: for (int i = sb.length() - 1; i > 0; i--) {
221: char ch = sb.charAt(i);
222: if (!Character.isJavaIdentifierPart(ch))
223: sb.deleteCharAt(i);
224: else
225: break;
226: }
227: sb = new StringBuffer(makeValidJavaBeanName(sb.toString()));
228:
229: // replace any remaining internal bad chars with underscores
230: for (int i = 0; i < sb.length(); i++) {
231: char ch = sb.charAt(i);
232: if (!Character.isJavaIdentifierPart(ch))
233: sb.setCharAt(i, '_');
234: }
235:
236: // return the string, or null if there was nothing left
237: return (sb.length() > 0) ? sb.toString() : null;
238: }
239:
240: /**
241: * Extract the property name from a getter method name by removing the leading "get" & fixing
242: * case.
243: *
244: * @param mname The getter method name
245: * @param tryIs If true, the 'is' prefix is tested first
246: * @return The property name.
247: */
248: public static final String propertyName(String mname, boolean tryIs) {
249: if (tryIs && mname.startsWith("is"))
250: return Introspector.decapitalize(mname.substring(2, mname
251: .length()));
252: if (mname.startsWith("get"))
253: return Introspector.decapitalize(mname.substring(3, mname
254: .length()));
255: return null;
256: }
257:
258: /**
259: * Extract the event name from an add method name by removing the leading "add" and trailing
260: * "Listener", & fixing case.
261: *
262: * @param mname The adder method name
263: * @return The event name.
264: */
265: public static final String eventName(String mname) {
266: String add = "add"; //NOI18N
267: String listener = "Listener"; //NOI18N
268: if (mname.startsWith(add) && mname.endsWith(listener)) {
269: if (mname.length() > (add.length() + listener.length()))
270: return Introspector.decapitalize(mname.substring(add
271: .length(), mname.length() - listener.length()));
272: else
273: return ""; // Method name is just "addListener"
274: }
275: return null;
276: }
277:
278: /**
279: * <p>The set of reserved keywords in the Java language.</p>
280: */
281: protected static Set keywords = new HashSet();
282: static {
283: keywords.add("abstract");
284: keywords.add("boolean");
285: keywords.add("break");
286: keywords.add("byte");
287: keywords.add("case");
288: keywords.add("cast");
289: keywords.add("catch");
290: keywords.add("char");
291: keywords.add("class");
292: keywords.add("const");
293: keywords.add("continue");
294: keywords.add("default");
295: keywords.add("do");
296: keywords.add("double");
297: keywords.add("else");
298: keywords.add("extends");
299: keywords.add("final");
300: keywords.add("finally");
301: keywords.add("float");
302: keywords.add("for");
303: keywords.add("future");
304: keywords.add("generic");
305: keywords.add("goto");
306: keywords.add("if");
307: keywords.add("implements");
308: keywords.add("import");
309: keywords.add("inner");
310: keywords.add("instanceof");
311: keywords.add("int");
312: keywords.add("interface");
313: keywords.add("long");
314: keywords.add("native");
315: keywords.add("new");
316: keywords.add("null");
317: keywords.add("operator");
318: keywords.add("outer");
319: keywords.add("package");
320: keywords.add("private");
321: keywords.add("protected");
322: keywords.add("public");
323: keywords.add("rest");
324: keywords.add("return");
325: keywords.add("short");
326: keywords.add("static");
327: keywords.add("super");
328: keywords.add("switch");
329: keywords.add("synchronized");
330: keywords.add("this");
331: keywords.add("throw");
332: keywords.add("throws");
333: keywords.add("transient");
334: keywords.add("try");
335: keywords.add("var");
336: keywords.add("void");
337: keywords.add("volatile");
338: keywords.add("while");
339: }
340:
341: /**
342: * <p>Return a mangled version of the specified name if it conflicts with
343: * a Java keyword; </p>
344: *
345: * @param name Name to be potentially mangled
346: */
347: public static final String mangle(String name, int i) {
348: if (keywords.contains(name)) {
349: return (name + i);
350: } else {
351: return (name);
352: }
353: }
354:
355: public static final boolean isJavaKeyWord(String name) {
356: if (keywords.contains(name)) {
357: return true;
358: } else {
359: return false;
360: }
361: }
362:
363: public static String getBaseName(String name) {
364: while (name.length() > 1
365: && Character.isDigit(name.charAt(name.length() - 1)))
366: name = name.substring(0, name.length() - 1);
367: return makeValidJavaBeanName(name);
368: }
369:
370: private Naming() {
371: } // this class is not instantiable
372: }
|