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: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.utils;
042:
043: /**
044: * A class that can be used to obtain Java class or method name formatted in various ways.
045: *
046: * @author Ian Formanek
047: * @author Misha Dmitriev
048: */
049: public class MethodNameFormatter {
050: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
051:
052: private static final String BOOLEAN_TEXT = "boolean"; // NOI18N
053: private static final String CHAR_TEXT = "char"; // NOI18N
054: private static final String BYTE_TEXT = "byte"; // NOI18N
055: private static final String SHORT_TEXT = "short"; // NOI18N
056: private static final String INT_TEXT = "int"; // NOI18N
057: private static final String LONG_TEXT = "long"; // NOI18N
058: private static final String FLOAT_TEXT = "float"; // NOI18N
059: private static final String DOUBLE_TEXT = "double"; // NOI18N
060: private static final String VOID_TEXT = "void"; // NOI18N
061: private static final char BOOLEAN_CODE = 'Z'; // NOI18N
062: private static final char CHAR_CODE = 'C'; // NOI18N
063: private static final char BYTE_CODE = 'B'; // NOI18N
064: private static final char SHORT_CODE = 'S'; // NOI18N
065: private static final char INT_CODE = 'I'; // NOI18N
066: private static final char LONG_CODE = 'J'; // NOI18N
067: private static final char FLOAT_CODE = 'F'; // NOI18N
068: private static final char DOUBLE_CODE = 'D'; // NOI18N
069: private static final char VOID_CODE = 'V'; // NOI18N
070:
071: //~ Instance fields ----------------------------------------------------------------------------------------------------------
072:
073: private String className;
074: private String methodName;
075: private String params;
076: private String returnType;
077:
078: //~ Constructors -------------------------------------------------------------------------------------------------------------
079:
080: /**
081: * Creates a new methodNameFormatter for given class/method/signature.
082: * The method name and signature can be null, in which case the formatter works for class only.
083: *
084: * @param cname A fully qualified name of the class, or null if only formatting methods
085: * - e.g. "java/lang/String"
086: * @param mname A name of method, empty string or "<init>" for constructors or null if method is not specified
087: * - e.g. "concat"
088: * @param sig VM signature of method or null if method is not specified or <clinit> is the method
089: * - e.g. "(Ljava/lang/String;)Ljava/lang/String;"
090: */
091: public MethodNameFormatter(String cname, String mname, String sig) {
092: int curPos;
093: int idx1;
094: int idx2;
095: char nextChar;
096:
097: StringBuffer arrayIndicator = new StringBuffer();
098:
099: if (cname != null) {
100: this .className = cname.replace('/', '.'); // NOI18N
101: } else {
102: // can be null in case formatter is only interested in method formatting // NOI18N
103: this .className = "<unknown class>"; // NOI18N
104: }
105:
106: if (mname == null) {
107: // methodName can be null when class- or package-level view is used
108: params = ""; // NOI18N
109: returnType = ""; // NOI18N
110: } else {
111: if ("".equals(mname)) { // NOI18N
112: this .methodName = "<init>"; // NOI18N
113: } else {
114: this .methodName = mname;
115: }
116:
117: if ("<clinit>".equals(methodName)
118: || Wildcards.isMethodWildcard(methodName)) { // NOI18N
119: params = ""; // NOI18N
120: returnType = ""; // NOI18N
121: } else {
122: idx1 = sig.lastIndexOf(')') + 1; // NOI18N
123:
124: if ((idx1 > 0) && !"<init>".equals(methodName)) { // NOI18N
125: // For e.g. the "Thread" root node it may be zero; there was a bug with it when this method
126: // was hit for "Thread" in results export
127: returnType = sig.substring(idx1);
128: curPos = 0;
129:
130: while (returnType.charAt(curPos) == '[') { // NOI18N
131: arrayIndicator.append("[]"); // NOI18N
132: curPos++;
133: }
134:
135: nextChar = returnType.charAt(curPos++);
136:
137: if (nextChar == BOOLEAN_CODE) {
138: returnType = BOOLEAN_TEXT
139: + arrayIndicator.toString();
140: } else if (nextChar == CHAR_CODE) {
141: returnType = CHAR_TEXT
142: + arrayIndicator.toString();
143: } else if (nextChar == BYTE_CODE) {
144: returnType = BYTE_TEXT
145: + arrayIndicator.toString();
146: } else if (nextChar == SHORT_CODE) {
147: returnType = SHORT_TEXT
148: + arrayIndicator.toString();
149: } else if (nextChar == INT_CODE) {
150: returnType = INT_TEXT
151: + arrayIndicator.toString();
152: } else if (nextChar == LONG_CODE) {
153: returnType = LONG_TEXT
154: + arrayIndicator.toString();
155: } else if (nextChar == FLOAT_CODE) {
156: returnType = FLOAT_TEXT
157: + arrayIndicator.toString();
158: } else if (nextChar == DOUBLE_CODE) {
159: returnType = DOUBLE_TEXT
160: + arrayIndicator.toString();
161: } else if (nextChar == VOID_CODE) {
162: returnType = VOID_TEXT
163: + arrayIndicator.toString();
164: } else { // return type is a class
165: // Check if the class belongs to the java.lang.* package, and replace it with simple name if so.
166: // However, avoid doing so if it's from say java.lang.ref.* package - otherwise we'll get confusing
167: // names like ref.Reference
168: returnType = returnType.substring(curPos,
169: returnType.length() - 1); //strip "L" at the beginning
170: // and ";" at end
171:
172: if (returnType.startsWith("java/lang/")
173: && (returnType.indexOf('/', 10) == -1)) { // NOI18N
174: returnType = returnType.substring(10);
175: }
176:
177: returnType = returnType.replace('$', '.'); // NOI18N
178: returnType = returnType.replace('/', '.')
179: + arrayIndicator.toString(); // NOI18N
180: }
181: } else {
182: // constructor or no end parenthesis
183: returnType = ""; // NOI18N
184: }
185:
186: idx1 = sig.indexOf('(') + 1; // NOI18N
187: idx2 = sig.lastIndexOf(')'); // NOI18N
188:
189: if (idx2 > 0) {
190: String paramsString = sig.substring(idx1, idx2);
191: StringBuffer paramsBuf = new StringBuffer();
192: arrayIndicator.setLength(0);
193: curPos = 0;
194:
195: while (curPos < paramsString.length()) {
196: while (paramsString.charAt(curPos) == '[') { // NOI18N
197: arrayIndicator.append("[]"); // NOI18N
198: curPos++;
199: }
200:
201: nextChar = paramsString.charAt(curPos++);
202:
203: if (nextChar == BOOLEAN_CODE) {
204: paramsBuf.append(BOOLEAN_TEXT);
205: } else if (nextChar == CHAR_CODE) {
206: paramsBuf.append(CHAR_TEXT);
207: } else if (nextChar == BYTE_CODE) {
208: paramsBuf.append(BYTE_TEXT);
209: } else if (nextChar == SHORT_CODE) {
210: paramsBuf.append(SHORT_TEXT);
211: } else if (nextChar == INT_CODE) {
212: paramsBuf.append(INT_TEXT);
213: } else if (nextChar == LONG_CODE) {
214: paramsBuf.append(LONG_TEXT);
215: } else if (nextChar == FLOAT_CODE) {
216: paramsBuf.append(FLOAT_TEXT);
217: } else if (nextChar == DOUBLE_CODE) {
218: paramsBuf.append(DOUBLE_TEXT);
219: } else { // it's a class
220:
221: int startPos = curPos;
222:
223: while (paramsString.charAt(curPos) != ';') { // NOI18N
224: curPos++;
225: }
226:
227: String typeName = paramsString.substring(
228: startPos, curPos); //strip "L" at the beginning and ";" at end
229:
230: if (typeName.startsWith("java/lang/")
231: && (typeName.indexOf('/', 10) == -1)) { // NOI18N
232: typeName = typeName.substring(10); // NOI18N
233: }
234:
235: typeName = typeName.replace('$', '.'); // NOI18N
236: typeName = typeName.replace('/', '.'); // NOI18N
237: paramsBuf.append(typeName);
238: curPos++;
239: }
240:
241: if (arrayIndicator.length() > 0) {
242: paramsBuf.append(arrayIndicator.toString());
243: }
244:
245: arrayIndicator.setLength(0);
246:
247: if (curPos < paramsString.length()) {
248: paramsBuf.append(", "); // NOI18N
249: }
250: }
251:
252: params = paramsBuf.toString();
253: } else {
254: params = ""; // NOI18N
255: }
256: }
257: }
258: }
259:
260: //~ Methods ------------------------------------------------------------------------------------------------------------------
261:
262: /**
263: * @return formatted class name, using '.' to separate packages = e.g. "java.lang.String"
264: */
265: public String getFormattedClass() {
266: return className;
267: }
268:
269: /**
270: * @return formatted class and method name (with parameter types, but without its return type).
271: * Will return the same as getFormattedClass if method was not specified.
272: */
273: public String getFormattedClassAndMethod() {
274: if (methodName == null) {
275: return getFormattedClass();
276: } else {
277: return className + "." + getFormattedMethod(); // NOI18N
278: }
279: }
280:
281: /**
282: * @return formatted method name, with parameter types, but without the return type. Will return empty string
283: * if method was not specified.
284: */
285: public String getFormattedMethod() {
286: if (methodName == null) {
287: return ""; // NOI18N // Understanding is that class-level view is used
288: } else if ("<clinit>".equals(methodName)) { // NOI18N
289:
290: return methodName;
291: } else {
292: return methodName + "(" + getParamsString() + ")"; // NOI18N
293: }
294: }
295:
296: /**
297: * @return formatted class and method name (with parameter types and return type)
298: * Will return the same as getFormattedClass if method was not specified.
299: */
300: public String getFullFormattedClassAndMethod() {
301: if (methodName == null) {
302: return getFormattedClass();
303: } else {
304: return className + "." + getFullFormattedMethod(); // NOI18N
305: }
306: }
307:
308: /**
309: * @return formatted method name with parameter types and return type (return type not used if constructor).
310: * Will return empty string if method was not specified.
311: */
312: public String getFullFormattedMethod() {
313: if (methodName == null) {
314: return ""; // NOI18N // Understanding is that class-level view is used
315: } else if ("<clinit>".equals(methodName)) { // NOI18N
316:
317: return methodName;
318: } else if ("<init>".equals(methodName)) { // NOI18N
319:
320: return methodName + "(" + getParamsString() + ")"; // NOI18N
321: } else {
322: return methodName + "(" + getParamsString() + ") : "
323: + getReturnType(); // NOI18N
324: }
325: }
326:
327: /**
328: * @return parameters of the given method - formatted string -, empty string if the method has no parameters or
329: * no method was specified
330: */
331: public String getParamsString() {
332: return params;
333: }
334:
335: /**
336: * @return return type of the given method, empty String if void or method was not specified
337: */
338: public String getReturnType() {
339: return returnType;
340: }
341:
342: public String toString() {
343: return getFullFormattedClassAndMethod();
344: }
345:
346: private boolean isAllWildCard(String methodName) {
347: return methodName.equals("<all>") || methodName.equals("*"); // NOI18N
348: }
349: }
|