/* * Copyright 2010 the original author or authors. * * 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 org.openehealth.ipf.labs.maven.dsldoc.domain; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.thoughtworks.qdox.model.DocletTag; import com.thoughtworks.qdox.model.JavaClass; import com.thoughtworks.qdox.model.JavaMethod; import com.thoughtworks.qdox.model.JavaParameter; /** * Contains information for each module in a report. * * @author Jens Riemschneider */ public class Documentation { public static final String DSL_DOC_TAG = "DSLDoc"; public static final String DSL_TAG = "DSL"; private static final String LINK = "{@link "; private static final String CODE = "{@code "; private final List<ModuleInfo> modules = new ArrayList<ModuleInfo>(); private final Types types; /** * Constructs the documentation object. * @param types * the type info object. */ public Documentation(Types types) { this.types = types; } /** * Adds a DSL method to the documentation. * @param module * the module that contains the DSL method. * @param section * the section that contains the DSL method. * @param info * the method info. */ public void addMethod(String module, String section, MethodInfo info) { addModuleAndSection(module, section); getModule(module).addMethod(section, info); } private void addModuleAndSection(String module, String section) { ModuleInfo moduleInfo = getModule(module); if (moduleInfo == null) { moduleInfo = new ModuleInfo(module, types); modules.add(moduleInfo); } moduleInfo.addSection(section); } private ModuleInfo getModule(String module) { for (ModuleInfo moduleInfo : modules) { if (moduleInfo.getName().equals(module)) { return moduleInfo; } } return null; } public List<ModuleInfo> getModules() { return modules; } public Types getTypes() { return types; } public void registerMethod(String module, JavaClass cls, JavaMethod method) { if (method.getTagByName(DSL_DOC_TAG) != null) { validate(method); String section = getSection(method); List<ParamInfo> paramInfos = getParams(method); ParamInfo returnParam = getReturns(method); String dslDocLink = getDslDocLink(method); String comment = javaDoc2Html(method.getComment(), cls); MethodInfo methodInfo = new MethodInfo(method.getName(), comment, paramInfos, returnParam, dslDocLink); this.addMethod(module, section, methodInfo); } } private void validate(JavaMethod method) throws AssertionError { if (!method.isPublic()) { throw new AssertionError(method + " must be public"); } if (method.getComment() == null) { throw new AssertionError(method + " must have a comment"); } if (getDslDocLink(method) == null || getDslDocLink(method).isEmpty()) { throw new AssertionError(method + " must define a link to the DSL documentation via @" + DSL_DOC_TAG); } if (method.isStatic() && method.getParameters().length == 0) { throw new AssertionError("static " + method + " must have at least one parameter for the this reference"); } if (method.getReturns() == null) { throw new AssertionError(method + " must return a value if it is a DSL element"); } } private String getDslDocLink(JavaMethod method) { return getTagValue(method, DSL_DOC_TAG); } private String getTagValue(JavaMethod method, String tagName) { DocletTag tag = method.getTagByName(tagName); return tag != null ? tag.getValue() : null; } private String getSection(JavaMethod method) { if (method.isStatic()) { return method.getParameters()[0].getType().getFullQualifiedName(); } return method.getParentClass().getFullyQualifiedName(); } private ParamInfo getReturns(JavaMethod method) { String typeFull = method.getReturns().getFullQualifiedName(); return new ParamInfo(typeFull, "", types.resolveLink(typeFull)); } private List<ParamInfo> getParams(JavaMethod method) { boolean first = true; List<ParamInfo> paramInfos = new ArrayList<ParamInfo>(); for (JavaParameter param : method.getParameters()) { if (!first || !method.isStatic()) { String typeFull = param.getType().getFullQualifiedName(); paramInfos.add(new ParamInfo(typeFull, param.getName(), types.resolveLink(typeFull))); } first = false; } return paramInfos; } private List<String> getTaggedSuperTypes(JavaClass cls) { List<String> types = new ArrayList<String>(); types.addAll(getTagged(cls.getSuperJavaClass())); for (JavaClass superType : cls.getImplementedInterfaces()) { types.addAll(getTagged(superType)); } return types; } private List<String> getTagged(JavaClass superType) { if (superType == null) { return Collections.emptyList(); } if (superType.getTagByName(DSL_TAG) != null) { return Collections.singletonList(superType.getFullyQualifiedName()); } return getTaggedSuperTypes(superType); } private String javaDoc2Html(String comment, JavaClass cls) { comment = comment.replaceAll("\r\n", " "); while (comment.contains(CODE)) { int start = comment.indexOf(CODE); int end = comment.indexOf("}", start + CODE.length()); String text = comment.substring(start + CODE.length(), end); comment = replace(comment, start, end + 1, "<tt>" + text + "</tt>"); } while (comment.contains(LINK)) { int start = comment.indexOf(LINK); int end = comment.indexOf("}", start + LINK.length()); String orgLink = comment.substring(start + LINK.length(), end); String fullType = getTypeViaImports(cls, orgLink); String newLink = types.resolveLink(fullType); comment = replace(comment, start, end + 1, "<a href=\"" + newLink + "\" title=\"" + fullType + "\">" + orgLink + "</a>"); } return comment; } private String getTypeViaImports(JavaClass cls, String orgLink) { String[] imports = cls.getSource().getImports(); for (String importedClass : imports) { if (types.getTypeName(importedClass).equals(orgLink)) { return importedClass; } } return orgLink; } private static String replace(String str, int start, int end, String replacement) { return str.substring(0, start) + replacement + str.substring(end); } }