package io.myweb.processor;
import io.myweb.api.*;
import io.myweb.http.Method;
import io.myweb.http.MimeTypes;
import io.myweb.processor.model.ParsedMethod;
import io.myweb.processor.model.ParsedParam;
import io.myweb.processor.model.ServiceParam;
import javax.annotation.processing.Messager;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class MyParser extends AnnotationMessagerAware {
private final MyValidator myValidator;
public MyParser(Messager messager, MyValidator myValidator) {
super(messager);
this.myValidator = myValidator;
}
public ParsedMethod parse(ExecutableElement ee) throws Exception {
List<ParsedParam> parasedParams = extractMethodParams(ee);
return extractParsedMethod(ee, parasedParams);
}
private ParsedMethod extractParsedMethod(ExecutableElement ee, List<ParsedParam> params) throws Exception {
String destClass = ee.getEnclosingElement().toString();
String destMethod = ee.getSimpleName().toString();
String destMethodRetType = ee.getReturnType().toString();
Method httpMethod = null;
String httpUri = "/";
String produces = MimeTypes.MIME_TEXT_PLAIN;
ServiceParam service = null;
List<? extends AnnotationMirror> annotationMirrors = ee.getAnnotationMirrors();
for (AnnotationMirror am : annotationMirrors) {
Method m = extractHttpMethod(am);
if (httpMethod==null) {
httpMethod = m;
httpUri = validateAndExtractHttpUri(am, httpMethod, destMethodRetType, destMethod, params, ee);
}
else if (m!=null) throw new IllegalArgumentException("Duplicate annotations @"+httpMethod.toString()+" and @"+m.toString()+" for method "+destClass+"."+destMethod+"()");
produces = extractProducesAnnotation(am);
if (service==null) service = validateAndExtractServiceAnnotation(params, am, ee);
}
return new ParsedMethod(destClass, destMethod, destMethodRetType, params, httpMethod, httpUri, produces, service);
}
private ServiceParam validateAndExtractServiceAnnotation(List<ParsedParam> params, AnnotationMirror am, ExecutableElement ee) {
ServiceParam service = null;
String annotationName = am.getAnnotationType().toString();
if (BindService.class.getName().equals(annotationName)) {
String value = getAnnotationValue(am, "value");
service = myValidator.validateBindServiceAnnotation(value, params, ee, am);
}
return service;
}
private String validateAndExtractHttpUri(AnnotationMirror am, Method httpMethod, String destMethodRetType, String destMethod, List<ParsedParam> params, ExecutableElement ee) {
String annotationName = am.getAnnotationType().toString();
String httpUri = "/";
if (isHttpMethodAnnotation(annotationName)) {
httpUri = getAnnotationValue (am, "value");
myValidator.validateAnnotation(httpMethod, destMethodRetType, destMethod, params, httpUri, ee, am);
}
return httpUri;
}
private String getAnnotationValue(AnnotationMirror am, String name) {
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : am.getElementValues().entrySet()) {
if (name.equals(entry.getKey().getSimpleName().toString())) {
return entry.getValue().getValue().toString();
}
}
return null;
}
private boolean isHttpMethodAnnotation(String annotationName) {
return GET.class.getName().equals(annotationName) || POST.class.getName().equals(annotationName)
|| DELETE.class.getName().equals(annotationName) || PUT.class.getName().equals(annotationName);
}
private Method extractHttpMethod(AnnotationMirror am) {
String annotationName = am.getAnnotationType().toString();
Method httpMethod = null;
if (isHttpMethodAnnotation(annotationName)) {
httpMethod = Method.findByName(annotationName.substring(annotationName.lastIndexOf(".") + 1).trim());
}
return httpMethod;
}
private String extractProducesAnnotation(AnnotationMirror am) {
String produces = MimeTypes.MIME_TEXT_HTML;
String annotationName = am.getAnnotationType().toString();
if (Produces.class.getName().equals(annotationName)) {
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : am.getElementValues().entrySet()) {
if ("value".equals(entry.getKey().getSimpleName().toString())) {
produces = entry.getValue().getValue().toString();
}
}
}
return produces;
}
private List<ParsedParam> extractMethodParams(ExecutableElement ee) {
List<? extends VariableElement> parameters = ee.getParameters();
List<ParsedParam> params = new LinkedList<ParsedParam>();
int i = 0;
for (VariableElement p : parameters) {
ParsedParam pp = extractMethodParam(i++, p);
params.add(pp);
}
return params;
}
private ParsedParam extractMethodParam(int paramNumber, VariableElement variableElement) {
ParsedParam pp = null;
try {
String type = variableElement.asType().toString().replaceFirst("class ", "");
pp = new ParsedParam(paramNumber, type, variableElement.getSimpleName().toString());
} catch (ClassNotFoundException e) {
error("cannot load class: " + e.getMessage());
}
return pp;
}
}