/**
* Mule Development Kit
* Copyright 2010-2011 (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
*
* 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.mule.devkit.validation;
import org.apache.commons.lang.StringUtils;
import org.mule.api.annotations.Configurable;
import org.mule.api.annotations.Connect;
import org.mule.api.annotations.Disconnect;
import org.mule.api.annotations.Processor;
import org.mule.api.annotations.Source;
import org.mule.api.annotations.Transformer;
import org.mule.devkit.GeneratorContext;
import org.mule.devkit.generation.DevKitTypeElement;
import org.mule.util.IOUtils;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class JavaDocValidator implements Validator {
@Override
public boolean shouldValidate(DevKitTypeElement typeElement, GeneratorContext context) {
return typeElement.isModuleOrConnector() && !context.isEnvOptionSet("skipJavaDocValidation");
}
@Override
public void validate(DevKitTypeElement typeElement, GeneratorContext context) throws ValidationException {
if (!hasComment(typeElement.getInnerTypeElement(), context)) {
throw new ValidationException(typeElement, "Class " + typeElement.getQualifiedName().toString() + " is not properly documented. A summary is missing.");
}
if (!context.getJavaDocUtils().hasTag("author", typeElement.getInnerTypeElement())) {
throw new ValidationException(typeElement, "Class " + typeElement.getQualifiedName().toString() + " needs to have an @author tag.");
}
for (VariableElement variable : typeElement.getFieldsAnnotatedWith(Configurable.class)) {
if (!hasComment(variable, context)) {
throw new ValidationException(variable, "Field " + variable.getSimpleName().toString() + " is not properly documented. The description is missing.");
}
}
for (ExecutableElement method : typeElement.getMethodsAnnotatedWith(Processor.class)) {
validateMethod(typeElement, context, method);
}
for (ExecutableElement method : typeElement.getMethodsAnnotatedWith(Source.class)) {
validateMethod(typeElement, context, method);
}
for (ExecutableElement method : typeElement.getMethodsAnnotatedWith(Transformer.class)) {
validateMethod(typeElement, context, method);
}
for (ExecutableElement method : typeElement.getMethodsAnnotatedWith(Connect.class)) {
validateAllParameters(context, method);
}
for (ExecutableElement method : typeElement.getMethodsAnnotatedWith(Disconnect.class)) {
validateAllParameters(context, method);
}
}
private void validateAllParameters(GeneratorContext context, ExecutableElement method) throws ValidationException {
for (VariableElement variable : method.getParameters()) {
if (!hasParameterComment(variable.getSimpleName().toString(), variable.getEnclosingElement(), context)) {
throw new ValidationException(variable, "Parameter " + variable.getSimpleName().toString() + " of method " + method.getSimpleName().toString() + " is not properly documented. A matching @param in the method documentation was not found. ");
}
}
}
private void validateMethod(DevKitTypeElement typeElement, GeneratorContext context, ExecutableElement method) throws ValidationException {
if (!hasComment(method, context)) {
throw new ValidationException(method, "Method " + method.getSimpleName().toString() + " is not properly documented. A description of what it can do is missing.");
}
if (!method.getReturnType().toString().equals("void") &&
!method.getReturnType().toString().contains("StopSourceCallback")) {
if (!context.getJavaDocUtils().hasTag("return", method)) {
throw new ValidationException(typeElement, "The return type of a non-void method must be documented. Method " + method.getSimpleName().toString() + " is at fault. Missing @return.");
}
}
if (exampleDoesNotExist(context, method)) {
throw new ValidationException(typeElement, "Method " + method.getSimpleName().toString() + " does not have the example pointed by the {@sample.xml} tag");
}
validateAllParameters(context, method);
}
private boolean hasComment(Element element, GeneratorContext context) {
String comment = context.getJavaDocUtils().getSummary(element);
return StringUtils.isNotBlank(comment);
}
private boolean hasParameterComment(String paramName, Element element, GeneratorContext context) {
String comment = context.getJavaDocUtils().getParameterSummary(paramName, element);
return StringUtils.isNotBlank(comment);
}
protected boolean exampleDoesNotExist(GeneratorContext context, ExecutableElement method) throws ValidationException {
if (!context.getJavaDocUtils().hasTag("sample.xml", method)) {
throw new ValidationException(method, "Method " + method.getSimpleName().toString() + " does not contain an example using {@sample.xml} tag.");
}
boolean found = false;
String sample = context.getJavaDocUtils().getTagContent("sample.xml", method);
String[] split = sample.split(" ");
if (split.length != 2) {
throw new ValidationException(method, "Check @sample.xml javadoc tag because is not well formed for method: " + method.getSimpleName());
}
String pathToExamplesFile = split[0];
String exampleName = split[1];
TypeElement typeElement = (TypeElement) method.getEnclosingElement();
String sourcePath = context.getSourceUtils().getPath(typeElement);
int packageCount = StringUtils.countMatches(typeElement.getQualifiedName().toString(), ".") + 1;
while (packageCount > 0) {
sourcePath = sourcePath.substring(0, sourcePath.lastIndexOf("/"));
packageCount--;
}
try {
File docFile = new File(sourcePath, pathToExamplesFile);
String examplesFileContent = IOUtils.toString(new FileInputStream(docFile));
if (examplesFileContent.contains("BEGIN_INCLUDE(" + exampleName + ")")) {
found = true;
}
} catch (IOException e) {
// do nothing
}
return !found;
}
}