be.idamediafoundry.sofa.livecycle.dsc.util.AbstractQDoxComponentInfoExtractor.java Source code

Java tutorial

Introduction

Here is the source code for be.idamediafoundry.sofa.livecycle.dsc.util.AbstractQDoxComponentInfoExtractor.java

Source

/*
 * Copyright 2012-2013 iDA MediaFoundry (www.ida-mediafoundry.be)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package be.idamediafoundry.sofa.livecycle.dsc.util;

import java.io.File;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import be.idamediafoundry.sofa.livecycle.maven.component.configuration.OperationType;

import com.thoughtworks.qdox.JavaDocBuilder;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaPackage;
import com.thoughtworks.qdox.model.JavaParameter;
import com.thoughtworks.qdox.model.Type;
import org.apache.maven.plugin.logging.Log;

/**
 * Extracts component info from java classes using the QDox framework.
 * 
 * @author Mike Seghers
 * 
 */
public abstract class AbstractQDoxComponentInfoExtractor
        implements ComponentInfoExtractor<JavaClass, JavaMethod, JavaMethod, JavaParameter, Type> {
    protected static final String DEFAULT_OUT_PARAM_NAME = "out";
    protected static final String RETURN_TAG = "return";
    protected static final String PARAM_TAG = "param";

    private JavaDocBuilder builder;
    private Log log;

    public AbstractQDoxComponentInfoExtractor(String sourcePath, Log log) {
        this.builder = new JavaDocBuilder();
        this.builder.addSourceTree(new File(sourcePath));
        this.log = log;
    }

    final public List<JavaClass> getServicesInfo() {
        List<JavaClass> result = new ArrayList<JavaClass>();

        JavaPackage[] packages = builder.getPackages();
        for (JavaPackage javaPackage : packages) {

            JavaClass[] classes = javaPackage.getClasses();
            for (JavaClass javaClass : classes) {
                if (acceptAsService(javaClass)) {
                    result.add(javaClass);
                }
            }
        }
        return result;
    }

    final public List<JavaMethod> getOperationsInfo(JavaClass serviceInfo) {
        List<JavaMethod> result = new ArrayList<JavaMethod>();
        JavaMethod[] methods = serviceInfo.getMethods();
        for (JavaMethod javaMethod : methods) {
            if (acceptAsOperation(javaMethod)) {
                result.add(javaMethod);
            }
        }
        return result;
    }

    final public List<JavaMethod> getConfigParametersInfo(JavaClass serviceInfo) {
        List<JavaMethod> result = new ArrayList<JavaMethod>();
        JavaMethod[] methods = serviceInfo.getMethods();
        for (JavaMethod javaMethod : methods) {
            if (acceptAsConfigParameter(javaMethod)) {
                result.add(javaMethod);
            }
        }
        return result;
    }

    final public List<JavaParameter> getOperationInputParameters(JavaMethod operationInfo) {
        List<JavaParameter> result = new ArrayList<JavaParameter>();
        JavaParameter[] parameters = operationInfo.getParameters();
        for (JavaParameter javaParameter : parameters) {
            result.add(javaParameter);
        }
        return result;
    }

    final public List<Type> getOperationFaults(JavaMethod operationInfo) {
        List<Type> result = new ArrayList<Type>();
        Type[] exceptions = operationInfo.getExceptions();
        for (Type exception : exceptions) {
            result.add(exception);
        }
        return result;
    }

    public abstract boolean acceptAsService(JavaClass javaClass);

    public abstract boolean acceptAsOperation(JavaMethod javaMethod);

    public abstract boolean acceptAsConfigParameter(JavaMethod javaMethod);

    /**
     * Generate the operation name, method and title attributes. This method
     * will check for duplicates (overloaded methods) and generate a different
     * method name for these overloaded methods, also setting the method
     * attribute in the process (otherwise not needed). If the method seems to
     * be overloaded, then the operationName tag in the javadoc is looked up. If
     * it does not exist, a long name will be generated using the concatenated
     * method name and parameter names and their types.
     * 
     * @param operationList
     *            the operation list to check for overloaded methods
     * @param javaMethod
     *            the java method
     * @param operation
     *            the operation
     */
    final protected void generateOperationNameMethodTitle(final List<String> existingOperationNames,
            final JavaMethod javaMethod, final OperationType operation, String suggestedName) {
        JavaParameter[] parameters = javaMethod.getParameters();
        String methodName = javaMethod.getName();
        String operationName;

        if (existingOperationNames.contains(methodName)) {
            // An overloaded method has been found, we will need to generate a
            // name
            // Let's see if the developer specified his preference
            if (StringUtils.isNotBlank(suggestedName)) {
                // Yes, he did!
                if (existingOperationNames.contains(suggestedName)) {
                    throw new RuntimeException("Could not generate component XML, the method " + methodName
                            + " in class " + javaMethod.getParentClass().getName()
                            + " has no unique operation name, please check your definition and make sure you specify a unique name");
                }
                operationName = suggestedName;
            } else {
                // Generate one, using the parameter names and types
                StringBuilder generated = new StringBuilder(methodName);
                generated.append("With");

                for (JavaParameter javaParameter : parameters) {
                    generated.append(StringUtils.capitalize(javaParameter.getName()));
                    generated.append("As");
                    generated.append(StringUtils.capitalize(javaParameter.getType().getJavaClass().getName()));
                }
                operationName = generated.toString();
                if (existingOperationNames.contains(operationName)) {
                    throw new RuntimeException(
                            "Could not generate component XML, the system could not generate a unique operation name for method "
                                    + methodName + " in class " + javaMethod.getParentClass().getName()
                                    + ", please check your definition and make sure you specify a unique name");
                }
            }
            operation.setMethod(methodName);
        } else {
            if (StringUtils.isNotBlank(suggestedName)) {
                operationName = suggestedName;
            } else {
                operationName = methodName;
            }
        }
        operation.setName(operationName);
        operation.setTitle(generateTitle(operationName));
    }

    /**
     * Generate an appropriate title for an element holding "title". The title
     * of an element is shown in the workbench as label for the operation,
     * configuration, input, output and fault elements. This method will make a
     * sentence of a camel cased string, transform it to lower case and finally
     * capitalize the first letter again.
     * 
     * @param base
     *            the camel cased string
     * @return the sentence
     */
    final protected String generateTitle(final String base) {
        return StringUtils
                .capitalize(StringUtils.join(StringUtils.splitByCharacterTypeCamelCase(base), ' ').toLowerCase());
    }

    /**
     * Get the fully qualified name from a Type object. If the type is a
     * generic, java.lang.Object is returned.
     * 
     * @param type
     *            the type
     * @return the fully qualified name
     */
    final protected String getFullyQualifiedJavaType(final Type type) {
        String strType;
        if (type.isResolved()) {
            strType = type.getFullyQualifiedName();
        } else {
            strType = "java.lang.Object";
        }
        return strType;
    }

    /**
     * Get the comments on a doc tag in a map (key is the first value in the doc
     * tag, the rest is the value).
     * 
     * @param javaMethod
     *            the java method in which to look for the tag
     * @param tagName
     *            the name of the tag
     * @return a map of comments for a certain tag name
     */
    final protected Map<String, String> getCommentMapForTag(final JavaMethod javaMethod, final String tagName) {
        DocletTag[] paramTags = javaMethod.getTagsByName(tagName);
        Map<String, String> paramTagMap = new HashMap<String, String>();
        for (DocletTag docletTag : paramTags) {
            String value = docletTag.getValue();
            paramTagMap.put(docletTag.getParameters()[0], value.substring(value.indexOf(' ') + 1));
        }
        return paramTagMap;
    }

    final protected Log getLog() {
        return log;
    }

    final protected String getFirstSentence(String text) {
        String result = text;
        if (text != null) {
            BreakIterator iterator = BreakIterator.getSentenceInstance();
            iterator.setText(text);
            int start = iterator.first();
            int end = iterator.next();
            if (end != BreakIterator.DONE) {
                result = text.substring(start, end).trim();
            }
        }
        return result;
    }
}