001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.java.language;
021    
022    import java.util.ArrayList;
023    import java.util.Arrays;
024    import java.util.Hashtable;
025    import java.util.List;
026    import java.util.Map;
027    
028    import org.apache.commons.lang.StringUtils;
029    
030    public class JavaMethodSignature {
031    
032      private final String methodName;
033      private final ReturnType returnType;
034      private final List<ArgumentType> argumentTypes;
035      private final boolean isConstructor;
036    
037      private static Map<String, JavaType> javaTypes = new Hashtable<String, JavaType>();
038      private static final char ARRAY = '[';
039    
040      static {
041        for (JavaType javaType : Arrays.asList(JavaType.values())) {
042          javaTypes.put(javaType.JVMTypeIdentifier, javaType);
043        }
044      }
045    
046      public JavaMethodSignature(String methodName, ReturnType returnType, ArgumentType... argumentTypes) {
047        this(methodName, returnType, Arrays.asList(argumentTypes));
048      }
049    
050      public JavaMethodSignature(String methodName, ReturnType returnType, List<ArgumentType> argumentTypes) {
051        this.methodName = methodName;
052        this.returnType = returnType;
053        this.argumentTypes = argumentTypes;
054        if (returnType == null) {
055          isConstructor = true;
056        } else {
057          isConstructor = false;
058        }
059    
060      }
061    
062      public static JavaMethodSignature create(String methodSignature) {
063        int leftBracketIndex = methodSignature.indexOf('(');
064        int rightBracketIndex = methodSignature.indexOf(')');
065        String methodName = methodSignature.substring(0, leftBracketIndex);
066        ReturnType returnType = extractReturnType(methodSignature.substring(rightBracketIndex + 1));
067        List<ArgumentType> argumentTypes = extractArgumentTypes(methodSignature.substring(leftBracketIndex + 1, rightBracketIndex));
068        return new JavaMethodSignature(methodName, returnType, argumentTypes);
069      }
070    
071      static List<ArgumentType> extractArgumentTypes(String argumentTypesSignature) {
072        List<ArgumentType> argumentTypes = new ArrayList<ArgumentType>();
073        int argumentTypeStartIndex = 0;
074        int argumentTypeEndIndex = 0;
075        while ((argumentTypeEndIndex = argumentTypesSignature.indexOf(';', argumentTypeStartIndex)) != -1) {
076          ArgumentType argumentAndReturnType = extractArgumentType(argumentTypesSignature.substring(argumentTypeStartIndex,
077              argumentTypeEndIndex));
078          argumentTypes.add(argumentAndReturnType);
079          argumentTypeStartIndex = argumentTypeEndIndex + 1;
080        }
081        return argumentTypes;
082      }
083    
084      private static ArgumentType extractArgumentType(String argumentTypeSignature) {
085        return new ArgumentType(extractType(argumentTypeSignature));
086      }
087    
088      private static ReturnType extractReturnType(String returnTypeSignature) {
089        if (StringUtils.isBlank(returnTypeSignature)) {
090          return null;
091        }
092        return new ReturnType(extractType(returnTypeSignature));
093      }
094    
095      static ArgumentAndReturnType extractType(String stringTypeSignature) {
096        boolean isArray = false;
097        int index = 0;
098        String classCanonicalName = null;
099        if (stringTypeSignature.charAt(0) == ARRAY) {
100          isArray = true;
101          index++;
102        }
103        JavaType javaType = javaTypes.get(stringTypeSignature.substring(index, index + 1));
104        index++;
105        if (javaType == JavaType.OBJECT) {
106          classCanonicalName = stringTypeSignature.substring(index);
107          classCanonicalName = StringUtils.remove(classCanonicalName, ';');
108        }
109        return new ArgumentType(javaType, classCanonicalName, isArray);
110      }
111    
112      public String dumpMethodSignature() {
113        StringBuilder builder = new StringBuilder();
114        builder.append(methodName);
115        builder.append("(");
116        for (ArgumentAndReturnType argumentType : argumentTypes) {
117          builder.append(dumpTypeSignature(argumentType));
118          builder.append(';');
119        }
120        builder.append(")");
121        if (!isConstructor) {
122          builder.append(dumpTypeSignature(returnType));
123          if (!returnType.isVoid()) {
124            builder.append(";");
125          }
126        }
127        return builder.toString();
128      }
129    
130      static String dumpTypeSignature(ArgumentAndReturnType argumentType) {
131        String result = "";
132        if (argumentType.isArray()) {
133          result += ARRAY;
134        }
135        result += argumentType.getJavaType().JVMTypeIdentifier;
136        if (argumentType.isOject()) {
137          result += argumentType.getClassCanonicalName();
138        }
139        return result;
140      }
141    }