Package com.iggroup.oss.restdoclet.doclet.util

Source Code of com.iggroup.oss.restdoclet.doclet.util.DocTypeUtils

/*
* #%L restdoc-doclet %% Copyright (C) 2012 IG Group %% 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. #L%
*/
package com.iggroup.oss.restdoclet.doclet.util;

import static com.iggroup.oss.restdoclet.doclet.util.AnnotationUtils.ignore;
import static com.iggroup.oss.restdoclet.doclet.util.UrlUtils.parseMultiUri;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.FieldDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.ParameterizedType;
import com.sun.javadoc.ProgramElementDoc;
import com.sun.javadoc.Tag;
import com.sun.javadoc.Type;

/**
* This is an utility class for processing document types.
*/
public final class DocTypeUtils {

   private static final Logger LOG = Logger.getLogger(DocTypeUtils.class);

   private static final String DEPRECATED_TAG = "uriDeprecated";
   private static final String RETURN_TAG = "return";
   private static final String IS_PREFIX = "is";
   private static final String GETTER_PREFIX = "get";

   /**
    * Private constructor to "silence" PMD.
    */
   private DocTypeUtils() {
      super();
   }

   /**
    * Return a string array of deprecated URIs for this element, searching for
    * DEPRECATED_TAG in the method comment
    *
    * @param element javadoc element
    * @return a string array of deprecated URIs for this element
    */
   public static String[] getDeprecatedURIs(final ProgramElementDoc element) {
      String[] uris = null;

      Tag[] tags = element.tags();

      for (final Tag tag : tags) {
         final String name = tag.name();
         if (StringUtils.contains(name, DEPRECATED_TAG)) {
            uris = parseMultiUri(tag.text());
            LOG.debug("deprecated uris" + tag.text());
            break;
         }
      }

      return uris;
   }

   /**
    * Generates a comment string from the given method, consisting of the
    * method return comment and if the return type is an iggroup type, a list
    * of attributes (separated by <br>
    * )
    *
    * @param element method doc
    * @return documentation string for the method
    */
   public static String getReturnDoc(final MethodDoc element) {

      LOG.info("Get return type documentation for method: "
         + element.toString());
      String doc = "";
      Tag[] tags = element.tags();

      String typeDoc = getTypeDoc(element.returnType());
      //if (typeComment.isEmpty()) { // no class doc found, revert to @return comment

      for (final Tag tag : tags) {
         final String name = tag.name();
         if (StringUtils.contains(name, RETURN_TAG)) {
            doc = tag.text();
            if (!typeDoc.isEmpty()) {
               doc += "<table><tr><td>" + typeDoc + "</td></tr></table>";
            }
            break;
         }
      }
      //}
      return doc;

   }

   /**
    * Return true if this is not a java type
    *
    * @param type
    * @return
    */
   private static Boolean isRelevantType(final Type type) {

      assert type.asClassDoc() != null;

      Boolean relevant =
         type != null && type.asClassDoc() != null
         && !ignore(type.asClassDoc())
         && type.asClassDoc().qualifiedTypeName().indexOf("java") != 0
         || isParameterisedType(type);

      LOG.debug(type + " relevance is " + relevant);
      return relevant;

   }

   /**
    * Return true if this this a parameterised type
    *
    * @param type
    * @return
    */
   private static Boolean isParameterisedType(final Type type) {

      return type.asParameterizedType() != null
         && type.asParameterizedType().typeArguments().length > 0;
   }

   /**
    * Log the type information
    *
    * @param type
    */
   private static void logType(final Type type) {

      if (LOG.isDebugEnabled() && type.asClassDoc() != null) {
         LOG.debug(type.asClassDoc().qualifiedTypeName());
         LOG.debug(" - " + type.asClassDoc().commentText());
         for (AnnotationDesc ad : type.asClassDoc().annotations()) {
            LOG.debug(" - " + ad.toString());
         }
      }

   }

   /**
    * Return the documentation for an enum type
    *
    * @param type
    * @return
    */
   private static String getEnumDoc(final Type type) {

      String typeInfo = "";

      if (type.asClassDoc() != null) {
         FieldDoc[] enumConstants = type.asClassDoc().enumConstants();
         for (FieldDoc constant : enumConstants) {
            typeInfo += "<TR>";
            typeInfo += "<TD>" + constant.name() + "</TD>";
            typeInfo += "<TD>" + constant.commentText() + "</TD>";
            typeInfo += "</TR>";
         }
      }

      return typeInfo;

   }

   /**
    * Return the documentation for a public constant
    *
    * @param type
    * @return
    */
   private static String getPublicConstantDoc(final Type type) {

      String typeInfo = "";

      FieldDoc[] fields = type.asClassDoc().fields(false);
      for (FieldDoc field : fields) {
         if (field.isPublic() && field.isFinal()
            && StringUtils.equals(field.name(), field.name().toUpperCase())) {

            typeInfo +=
               "<tr><td>" + field.type().simpleTypeName() + " " + field.name()
               + "</td><td>" + field.commentText() + "</td></tr>";

         }
      }

      return typeInfo;
   }

   /**
    * Return the documentation for a field
    *
    * @param type
    * @param attributeName
    * @return
    */
   private static String getFieldDoc(final Type type,
                                     final String attributeName,
                                     final String methodComment) {

      LOG.debug("getFieldDoc " + type.simpleTypeName() + " - " + attributeName
         + " - " + methodComment);
      String fieldComment = "";

      if (type.asClassDoc() != null) {
         for (FieldDoc field : type.asClassDoc().fields(false)) {
            if (field.name().equalsIgnoreCase(attributeName)) {
               fieldComment = field.commentText();
               if (methodComment.length() > fieldComment.length()) {
                  fieldComment = methodComment;
               }
               // see if there are any validation
               // constraints
               AnnotationDesc[] annotations = field.annotations();
               for (AnnotationDesc annotation : annotations) {
                  if (annotation.toString().contains(
                     "@javax.validation.constraints.")) {
                     String constraint =
                        annotation.toString().replace(
                           "@javax.validation.constraints.", "");
                     fieldComment += "<br>[Rule: " + constraint + "]";
                  }
               }
               break;
            }
         }
      }

      return fieldComment;

   }

   /**
    * Return a list of getter names
    *
    * @param type
    * @return
    */
   private static Collection<String> getGetterNames(final Type type) {

      FieldDoc[] fields = type.asClassDoc().fields(false);
      ArrayList<String> getterNames = new ArrayList<String>();
      for (FieldDoc field : fields) {
         if (!(field.isPublic() && field.isFinal() && StringUtils.equals(
            field.name(), field.name().toUpperCase()))) {
            getterNames.add(GETTER_PREFIX
               + field.name().substring(0, 1).toUpperCase()
               + field.name().substring(1));
            getterNames.add(IS_PREFIX
               + field.name().substring(0, 1).toUpperCase()
               + field.name().substring(1));
         }
      }

      return getterNames;

   }

   /**
    * Returns as a string a list of attributes plus comments for the given
    * iggroup complex type (or empty string if not iggroup), formatted in an
    * HTML table. This method will recurse if attributes are iggroup complex
    * types
    *
    * @param type
    * @param processedTypes
    * @param leafType
    * @return
    */
   private static String getTypeDoc(final Type type,
                                    HashMap<String, String> processedTypes,
                                    Boolean leafType) {

      LOG.info("getTypeDoc " + type + " leafType=" + leafType);

      String typeInfo = "";

      if (isRelevantType(type)) {

         ClassDoc typeDoc = type.asClassDoc();
         typeInfo = processedTypes.get(type.toString());
         if (typeInfo != null) {
            LOG.debug("Found cached typedoc for " + type.typeName() + " - "
               + typeInfo);
         }
         if (typeInfo == null && typeDoc != null) {

            typeInfo = "";

            // if this is a generic type then recurse with the first type argument
            if (isParameterisedType(type)) {

               LOG.debug("Parameterised type");
               if (type.asClassDoc() != null) {
                  typeInfo =
                     getTypeDoc(
                        type.asParameterizedType().typeArguments()[type
                                                                   .asParameterizedType().typeArguments().length - 1],
                                                                   processedTypes, true);
               }

            } else {

               logType(type);

               // put placeholder to stop recursion for self-referential types
               LOG.debug("Starting to cache: " + type.typeName());
               processedTypes.put(type.toString(), "");

               LOG.debug(typeDoc.commentText() + "  " + leafType);
               if (leafType && !typeDoc.commentText().isEmpty()) {
                  typeInfo +=
                     "<tr><span class=\"javadoc-header\">"
                        + typeDoc.commentText() + "</span></tr>";
                  LOG.debug(typeInfo);
               }

               if (typeDoc.isEnum()) {

                  LOG.debug("Enum type");
                  typeInfo += getEnumDoc(type);

               } else { // class

                  LOG.debug("Class");
                  // first do base class
                  if (typeDoc.superclass() != null) {

                     LOG.debug("base type = "
                        + typeDoc.superclass().qualifiedName());

                     String baseTypeDoc =
                        getTypeDoc(type.asClassDoc().superclassType(),
                           processedTypes, false);
                     if (!baseTypeDoc.isEmpty()) {
                        LOG.debug("base type DOC = " + baseTypeDoc);
                        typeInfo += baseTypeDoc;
                     }
                  }

                  typeInfo += getPublicConstantDoc(type);

                  Collection<String> getterNames = getGetterNames(type);

                  for (MethodDoc method : typeDoc.methods()) {

                     if (method.isPublic()
                        && getterNames.contains(method.name())
                        && !ignore(method)) {

                        String attributeInfo = "";
                        String attributeType =
                           method.returnType().simpleTypeName();

                        // check if is this a parameterised type
                        ParameterizedType pt =
                           method.returnType().asParameterizedType();
                        if (pt != null && pt.typeArguments().length > 0) {

                           attributeType += "[";
                           for (int i = 0; i < pt.typeArguments().length; i++) {
                              attributeType +=
                                 pt.typeArguments()[i].simpleTypeName();
                              if (i < pt.typeArguments().length - 1) {
                                 attributeType += ", ";
                              }
                           }
                           attributeType += "]";

                        }

                        // Check if this is an array
                        attributeType += method.returnType().dimension();

                        final String attributeName =
                           getAttributeNameFromMethod(method.name());

                        attributeInfo +=
                           "<td>" + attributeType + " " + attributeName
                           + "</td>";

                        // If type or parameterised type then recurse
                        LOG.debug("Generating attribute doc for "
                           + method.returnType());
                        String attributeTypeDoc =
                           getTypeDoc(method.returnType(), processedTypes,
                              true);
                        if (!attributeTypeDoc.isEmpty()) {
                           LOG.debug("Found attribute doc for "
                              + method.returnType());
                           attributeInfo +=
                              "<td>" + attributeTypeDoc + "</td>";

                        } else { // no useful type information, so use whatever's on the attribute doc
                           LOG.debug("Found no attribute doc for "
                              + method.returnType());

                           String fieldDoc =
                              getFieldDoc(type, attributeName,
                                 method.commentText());
                           attributeInfo += "<td>" + fieldDoc + "</td>";

                        }

                        if (!attributeInfo.isEmpty()) {
                           typeInfo += "<tr>" + attributeInfo + "</tr>";
                        }

                     }
                  }
               }

               // Wrap in a table tag if this is concrete type
               if (leafType && !typeInfo.isEmpty()) {
                  typeInfo = "<table>" + typeInfo + "</table>";
               }
            }

         }

         LOG.debug("Caching: " + type);
         processedTypes.put(type.toString(), typeInfo);

      }

      if (typeInfo == null) {
         typeInfo = "";
      }
      LOG.debug("XXX " + type.typeName() + " XXX " + typeInfo);
      return typeInfo;

   }

   /**
    * Returns as a string a list of attributes plus comments for the given
    * type, separated by <br>
    * This method will recurse if attributes are non java types
    *
    * @param type type info
    * @return attribute data for the given type
    */
   public static String getTypeDoc(final Type type) {
      HashMap<String, String> documentedTypes = new HashMap<String, String>();
      String typeDoc = getTypeDoc(type, documentedTypes, true);
      if (typeDoc != null && !typeDoc.trim().isEmpty()) {
         LOG.info("Got documentation for type " + type + " : " + typeDoc);
      }
      return typeDoc;
   }

   /**
    * Return the simple type name of the passed in type, and include the simple
    * name of the template type if a generic
    *
    * @param type type info
    * @return simple type name (including template type name in [] if
    *         applicable)
    */
   public static String getTypeName(final Type type) {

      String typeName = "";
      typeName = type.simpleTypeName();
      ParameterizedType pt = type.asParameterizedType();
      if (pt != null && pt.typeArguments() != null
         && pt.typeArguments().length > 0) {
         typeName += "[";
         for (int i = 0; i < pt.typeArguments().length; i++) {
            typeName += pt.typeArguments()[i].simpleTypeName();
            if (i < pt.typeArguments().length - 1) {
               typeName += ", ";
            }
         }
         typeName += "]";
      }
      return typeName;

   }

   /**
    * Derive an attribute name from a getter/setter
    *
    * @param methodName
    * @return the methodName without the leading is/get/set
    */
   private static String getAttributeNameFromMethod(String methodName) {

      String attributeName;
      if (methodName.startsWith(IS_PREFIX)) {
         attributeName = methodName.substring(IS_PREFIX.length());
      } else {
         attributeName = methodName.substring(GETTER_PREFIX.length());
      }

      if (attributeName != null && !attributeName.isEmpty()) {
         attributeName =
            attributeName.substring(0, 1).toLowerCase()
            + attributeName.substring(1);
      }

      return attributeName;
   }

}
TOP

Related Classes of com.iggroup.oss.restdoclet.doclet.util.DocTypeUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.