001    /***
002     *
003     * Copyright (c) 2007 Paul Hammant
004     * All rights reserved.
005     *
006     * Redistribution and use in source and binary forms, with or without
007     * modification, are permitted provided that the following conditions
008     * are met:
009     * 1. Redistributions of source code must retain the above copyright
010     *    notice, this list of conditions and the following disclaimer.
011     * 2. Redistributions in binary form must reproduce the above copyright
012     *    notice, this list of conditions and the following disclaimer in the
013     *    documentation and/or other materials provided with the distribution.
014     * 3. Neither the name of the copyright holders nor the names of its
015     *    contributors may be used to endorse or promote products derived from
016     *    this software without specific prior written permission.
017     *
018     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028     * THE POSSIBILITY OF SUCH DAMAGE.
029     */
030    package com.thoughtworks.paranamer.generator;
031    
032    import com.thoughtworks.qdox.JavaDocBuilder;
033    import com.thoughtworks.qdox.model.JavaClass;
034    import com.thoughtworks.qdox.model.JavaMethod;
035    import com.thoughtworks.qdox.model.JavaParameter;
036    
037    import java.io.File;
038    import java.io.IOException;
039    import java.util.*;
040    
041    /**
042     * Qdox-based implementation of ParanamerGenerator which parses Java source files to processSourcePath
043     * parameter names lists.
044     * 
045     * @author Paul Hammant
046     * @author Mauro Talevi
047     * @author Guilherme Silveira
048     */
049    public class QdoxParanamerGenerator implements ParanamerGenerator {
050    
051        private static final String SPACE  = " ";
052        private static final String NEWLINE = "\n";
053        private static final String COMMA = ",";
054        private static final String EMPTY = "";
055    
056        public QdoxParanamerGenerator() {
057        }
058    
059        public void processSourcePath(String sourcePath, String outputPath) throws IOException {
060            JavaClass[] classes = getClassesSortedByName(sourcePath);
061            processClasses(classes, outputPath);
062        }
063    
064        private JavaClass[] getClassesSortedByName(String sourcePath) {
065            JavaDocBuilder builder = new JavaDocBuilder();
066            builder.addSourceTree(new File(sourcePath));
067            JavaClass[] classes = builder.getClasses();
068            Arrays.sort(classes);
069            return classes;
070        }
071    
072        public void processClasses(JavaClass[] classes, String outputPath) throws IOException {
073            for (JavaClass javaClass : classes) {
074                String content = addMethods(javaClass.getMethods());
075                // TODO problem with inner classes
076                makeEnhancer().enhance(new File(outputPath, javaClass.getFullyQualifiedName().replace('.', File.separatorChar) + ".class"), content);
077    
078            }
079        }
080    
081        public Enhancer makeEnhancer() {
082            return new Enhancer();
083        }
084    
085        private String addMethods(JavaMethod[] methods) {
086            Arrays.sort(methods);
087            StringBuffer buffer = new StringBuffer();
088            for (JavaMethod javaMethod : methods) {
089                if (!Arrays.asList(javaMethod.getModifiers()).contains("private")
090                        && javaMethod.getParameters().length > 0) {
091                    buffer.append(addMethod(javaMethod));
092                }
093            }
094            return buffer.toString();
095        }
096    
097        private String addMethod(JavaMethod method) {
098            JavaParameter[] parameters = method.getParameters();
099            return format(method, parameters);
100        }
101    
102        private String format(JavaMethod method, JavaParameter[] parameters) {
103            StringBuffer sb = new StringBuffer();
104            String methodName = method.getName();
105            if (method.isConstructor()) {
106                methodName = "<init>";
107            }
108            String parameterTypes = getParameterTypes(parameters);
109            sb.append(formatLine(methodName, parameterTypes, getParameterNames(parameters)));
110            return sb.toString();
111        }
112    
113        private String formatLine(String methodName, String paramTypes, String paramNames){
114            StringBuffer sb = new StringBuffer();
115            // processClasses line structure:  methodName paramTypes paramNames
116            sb.append(methodName).append(SPACE);
117            if ( paramTypes.length() > 0 ) {
118                sb.append(paramTypes.trim()).append(SPACE);
119                sb.append(paramNames.trim()).append(SPACE);
120            }
121            sb.append(NEWLINE);
122            return sb.toString();
123        }
124    
125        private String getParameterNames(JavaParameter[] parameters) {
126            StringBuffer sb = new StringBuffer();
127            for (int i = 0; i < parameters.length; i++) {
128                sb.append(parameters[i].getName());
129                sb.append(comma(i, parameters.length));
130            }
131            return sb.toString();
132        }
133    
134        private String getParameterTypes(JavaParameter[] parameters) {
135            StringBuffer sb = new StringBuffer();
136            for (int i = 0; i < parameters.length; i++) {
137                sb.append(parameters[i].getType());
138                sb.append(comma(i, parameters.length));
139            }
140            return sb.toString();
141        }
142    
143        private String comma(int index, int size) {
144            return (index + 1 < size) ? COMMA : EMPTY;
145        }
146    
147    }