001    package org.shiftone.jrat.core;
002    
003    
004    import org.shiftone.jrat.util.Assert;
005    import org.shiftone.jrat.util.log.Logger;
006    
007    import java.util.ArrayList;
008    import java.util.HashMap;
009    import java.util.List;
010    import java.util.Map;
011    
012    
013    /**
014     * @author jeff@shiftone.org (Jeff Drost)
015     */
016    public class Signature {
017    
018        private static final Logger LOG = Logger.getLogger(Signature.class);
019        private static Map PRIM_CODES = new HashMap();
020        private String returnType;
021        private List parameterTypes = new ArrayList(5);
022    
023        static {
024            PRIM_CODES.put("Z", "boolean");
025            PRIM_CODES.put("B", "byte");
026            PRIM_CODES.put("C", "char");
027            PRIM_CODES.put("D", "double");
028            PRIM_CODES.put("F", "float");
029            PRIM_CODES.put("I", "int");
030            PRIM_CODES.put("J", "long");
031            PRIM_CODES.put("S", "short");
032            PRIM_CODES.put("V", "void");
033        }
034    
035        public Signature(String descriptors) {
036            parseSig(new CharacterIterator(descriptors));
037        }
038    
039    
040        public String getReturnType() {
041            return returnType;
042        }
043    
044    
045        public int getParameterCount() {
046            return parameterTypes.size();
047        }
048    
049    
050        public String getParameterType(int index) {
051            return (String) parameterTypes.get(index);
052        }
053    
054    
055        public String getShortParameterType(int index) {
056    
057            String type = getParameterType(index);
058            int dotIndex = type.lastIndexOf('.');
059    
060            if (dotIndex != -1) {
061                type = type.substring(dotIndex + 1);
062            }
063    
064            return type;
065        }
066    
067    
068        public String getShortText() {
069    
070            StringBuffer sb = new StringBuffer();
071    
072            for (int i = 0; i < getParameterCount(); i++) {
073                if (i != 0) {
074                    sb.append(",");
075                }
076    
077                sb.append(getShortParameterType(i));
078            }
079    
080            return sb.toString();
081        }
082    
083    
084        public String getLongText() {
085    
086            StringBuffer sb = new StringBuffer();
087    
088            for (int i = 0; i < getParameterCount(); i++) {
089                if (i != 0) {
090                    sb.append(",");
091                }
092    
093                sb.append(getParameterType(i));
094            }
095    
096            return sb.toString();
097        }
098    
099    
100        private void parseSig(CharacterIterator in) {
101    
102            Assert.assertTrue("first char is (", in.next() && (in.get() == '('));
103    
104            boolean inParams = true;
105    
106            while (in.next()) {
107                char c = in.get();
108    
109                if (c == ')') {
110                    inParams = false;
111                }
112    
113                if (inParams) {
114                    parameterTypes.add(parseType(in));
115                } else {
116                    returnType = parseType(in);
117                }
118            }
119        }
120    
121    
122        private String parseType(CharacterIterator in) {
123    
124            char c = in.get();
125    
126            if (c == 'L') {
127                return parseClassType(in);
128            } else if (c == '[') {
129                return parseArrayType(in);
130            } else {
131                return (String) PRIM_CODES.get(String.valueOf(c));
132            }
133        }
134    
135    
136        private String parseArrayType(CharacterIterator in) {
137    
138            StringBuffer sb = new StringBuffer("[]");
139    
140            while (in.next() && (in.get() == '[')) {
141                sb.append("[]");
142            }
143    
144            sb.insert(0, parseType(in));    // out the type at the start of the
145    
146            // [][][]
147            return sb.toString();
148        }
149    
150    
151        private String parseClassType(CharacterIterator in) {
152    
153            StringBuffer className = new StringBuffer();
154    
155            while (in.next()) {
156                char c = in.get();
157    
158                if (c == ';') {
159                    break;
160                } else if (c == '/') {
161                    className.append('.');
162                } else {
163                    className.append(c);
164                }
165            }
166    
167            return className.toString();
168        }
169    
170    
171        // todo - this is handy - make it common
172        private static class CharacterIterator {
173    
174            private char[] chars;
175            private int pos = -1;
176            private char current;
177    
178            public CharacterIterator(String text) {
179                this.chars = text.toCharArray();
180            }
181    
182    
183            public CharacterIterator(char[] chars) {
184                this.chars = chars;
185            }
186    
187    
188            public boolean next() {
189    
190                pos++;
191    
192                if (pos >= chars.length) {
193                    return false;
194                } else {
195                    current = chars[pos];
196    
197                    return true;
198                }
199            }
200    
201    
202            public char get() {
203                return current;
204            }
205        }
206    }