package org.distributeme.generator;
import net.anotheria.util.StringUtils;
import org.distributeme.annotation.ConcurrencyControlClientSideLimit;
import org.distributeme.annotation.ConcurrencyControlLimit;
import org.distributeme.annotation.ConcurrencyControlServerSideLimit;
import org.distributeme.annotation.Route;
import org.distributeme.core.ClientSideCallContext;
import org.distributeme.core.Defaults;
import org.distributeme.core.interceptor.InterceptionPhase;
import org.distributeme.core.routing.Router;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Base generator class.
*
* @author lrosenberg
* @version $Id: $Id
*/
public class AbstractGenerator {
/**
* PrintWriter for output generations.
*/
private PrintWriter writer;
private final ProcessingEnvironment environment;
/**
* Counter for concurrency control creation methods.
*/
private static AtomicInteger ccOrders = new AtomicInteger();
/**
* Counter for router creation methods.
*/
private static AtomicInteger routerOrders = new AtomicInteger();
/**
* <p>Constructor for AbstractGenerator.</p>
*
* @param environment a {@link javax.annotation.processing.ProcessingEnvironment} object.
*/
public AbstractGenerator(ProcessingEnvironment environment) {
this.environment = environment;
}
/**
* <p>Setter for the field <code>writer</code>.</p>
*
* @param aWriter a {@link java.io.Writer} object.
*/
protected void setWriter(Writer aWriter){
writer = new PrintWriter(aWriter);
resetIdent();
}
/**
* <p>Getter for the field <code>writer</code>.</p>
*
* @return a {@link java.io.Writer} object.
*/
protected Writer getWriter(){
return writer;
}
/**
* Returns the name of the generated Remote interface for a type.
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getRemoteInterfaceName(TypeElement type){
return "Remote"+type.getSimpleName().toString();
}
/**
* <p>getAsynchInterfaceName.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getAsynchInterfaceName(TypeElement type){
return "Asynch"+type.getSimpleName().toString();
}
/**
* Returns the name of the generated Stub class for a type.
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getStubName(TypeElement type){
return "Remote"+type.getSimpleName().toString()+"Stub";
}
/**
* <p>getJaxRsStubName.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getJaxRsStubName(TypeElement type){
return type.getSimpleName().toString()+"JaxRsStub";
}
/**
* <p>getAsynchStubName.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getAsynchStubName(TypeElement type){
return "Asynch"+type.getSimpleName().toString()+"Stub";
}
/**
* <p>getDefaultImplFactoryName.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
public static final String getDefaultImplFactoryName(TypeElement type){
return type.getQualifiedName()+"Factory";
}
/**
* Returns the name of the generated Skeleton class for a type.
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getSkeletonName(TypeElement type){
return "Remote"+type.getSimpleName().toString()+"Skeleton";
}
/**
* <p>getResourceName.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getResourceName(TypeElement type){
return type.getSimpleName().toString()+"Resource";
}
/**
* <p>getConstantsName.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getConstantsName(TypeElement type){
return type.getSimpleName().toString()+"Constants";
}
/**
* <p>getFactoryName.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getFactoryName(TypeElement type){
return "Remote"+type.getSimpleName().toString()+"Factory";
}
/**
* <p>getAsynchFactoryName.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getAsynchFactoryName(TypeElement type){
return "Asynch"+type.getSimpleName().toString()+"Factory";
}
/**
* <p>getServerName.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getServerName(TypeElement type){
String name = type.getSimpleName().toString().toString();
return getServerName(name);
}
/**
* Return the fully qualified name for the server class.
*
* @param interfaceName a {@link java.lang.String} object.
* @return a {@link java.lang.String} object.
*/
protected static String getFullyQualifiedServerName(String interfaceName){
int indexOfDot = interfaceName.lastIndexOf('.');
String packageName = "";
if (indexOfDot!=-1){
packageName = interfaceName.substring(0, indexOfDot);
interfaceName = interfaceName.substring(indexOfDot+1);
}
packageName += ".generated.";
if (interfaceName.endsWith("Service"))
interfaceName = interfaceName.substring(0, interfaceName.length()-"Service".length());
return packageName+interfaceName+"Server";
}
/**
* <p>getServerName.</p>
*
* @param interfaceName a {@link java.lang.String} object.
* @return a {@link java.lang.String} object.
*/
protected static String getServerName(String interfaceName){
int indexOfDot = interfaceName.lastIndexOf('.');
if (indexOfDot!=-1)
interfaceName = interfaceName.substring(indexOfDot+1);
if (interfaceName.endsWith("Service"))
interfaceName = interfaceName.substring(0, interfaceName.length()-"Service".length());
return interfaceName+"Server";
}
/**
* <p>getInterfaceName.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected static String getInterfaceName(TypeElement type){
return type.getSimpleName().toString().toString();
}
/**
* <p>getPackageOf.</p>
*
* @param type a {@link javax.lang.model.element.Element} object.
* @return a {@link javax.lang.model.element.PackageElement} object.
*/
protected PackageElement getPackageOf(Element type) {
Elements elements = environment.getElementUtils();
return elements.getPackageOf(type);
}
/**
* <p>getPackageName.</p>
*
* @param element a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getPackageName(TypeElement element){
return getPackageOf(element).getQualifiedName()+".generated";
}
/**
* <p>writePackage.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
*/
protected void writePackage(TypeElement type){
writeString("package "+getPackageName(type)+";");
}
/**
* Writes comments that disables analyzers like checkstyle.
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
*/
protected void writeAnalyzerComments(TypeElement type){
writeString("//CHECKSTYLE:OFF");
}
/**
* <p>quote.</p>
*
* @param s a {@link java.lang.String} object.
* @return a {@link java.lang.String} object.
*/
protected String quote(String s){
return "\""+s+"\"";
}
/**
* <p>quote.</p>
*
* @param o a {@link java.lang.Object} object.
* @return a {@link java.lang.String} object.
*/
protected String quote(Object o){
return "\""+o+"\"";
}
/**
* <p>quote.</p>
*
* @param s a {@link java.lang.StringBuilder} object.
* @return a {@link java.lang.String} object.
*/
protected String quote(StringBuilder s){
return "\""+s.toString()+"\"";
}
/**
* <p>quote.</p>
*
* @param a a int.
* @return a {@link java.lang.String} object.
*/
protected String quote(int a){
return quote(""+a);
}
/**
* <p>writeIncreasedString.</p>
*
* @param s a {@link java.lang.String} object.
*/
protected void writeIncreasedString(String s){
increaseIdent();
writeString(s);
decreaseIdent();
}
/**
* <p>writeIncreasedStatement.</p>
*
* @param s a {@link java.lang.String} object.
*/
protected void writeIncreasedStatement(String s){
writeIncreasedString(s+";");
}
/**
* Linefeed.
*/
public static final String CRLF = "\n";
/**
* Current ident.
*/
private int ident = 0;
/**
* Writes a string in a new line with ident and linefeed.
*
* @param s string to write.
*/
protected void writeString(String s){
StringBuilder ret = getIdent();
ret.append(s).append(CRLF);
writer.write(ret.toString());
}
//later replace with openTry
/**
* <p>openTry.</p>
*/
protected void openTry(){
writeString("try{");
increaseIdent();
}
/**
* <p>openFun.</p>
*
* @param s a {@link java.lang.String} object.
*/
protected void openFun(String s){
if (!s.endsWith("{"))
s+=" {";
writeString(s);
increaseIdent();
}
/**
* Writes a statement (';' at the end of the line)
*
* @param s statement to write.
*/
protected void writeStatement(String s){
StringBuilder ret = getIdent();
ret.append(s).append(";").append(CRLF);
writer.write(ret.toString());
}
/**
* Returns current ident as string.
* @return a string with "\t"s.
*/
private StringBuilder getIdent(){
StringBuilder ret = new StringBuilder();
for (int i=0; i<ident; i++)
ret.append("\t");
return ret;
}
/**
* increases current ident.
*/
protected void increaseIdent(){
ident++;
}
/**
* decreases current ident.
*/
protected void decreaseIdent(){
ident--;
if (ident<0)
ident = 0;
}
/**
* <p>resetIdent.</p>
*/
protected void resetIdent(){
ident = 0;
}
/**
* Appends an empty line.
*/
public void emptyline(){
writer.write(CRLF);
}
/**
* <p>writeImport.</p>
*
* @param imp a {@link java.lang.String} object.
*/
protected void writeImport(String imp){
writeString("import "+imp+";");
}
/**
* <p>writeImport.</p>
*
* @param clazz a {@link java.lang.Class} object.
*/
protected void writeImport(Class<?> clazz){
writeImport(clazz.getName());
}
/**
* <p>writeImport.</p>
*
* @param packagename a {@link java.lang.String} object.
* @param classname a {@link java.lang.String} object.
*/
protected void writeImport(String packagename, String classname){
writeString("import "+packagename+"."+classname+";");
}
/**
* Closes a previously opened code block by decreasing the ident and writing a closing '}'.
*/
protected void closeBlock(){
decreaseIdent();
writeString("}");
}
/**
* Closes a previously opened code block without decreasing the ident.
*/
protected void closeBlockWithoutIdent(){
writeString("}");
}
/**
* Closes a block and writes a comment.
*
* @param comment a {@link java.lang.String} object.
*/
protected void closeBlock(String comment){
decreaseIdent();
writeString("} //..."+comment);
}
/**
* Closes a block without ident and writes a comment.
*
* @param comment a {@link java.lang.String} object.
*/
protected void closeBlockWithoutIdent(String comment){
writeString("} //..."+comment);
}
/**
* <p>appendMark.</p>
*
* @param markNumber a int.
*/
protected void appendMark(int markNumber){
// String ret = "/* ***** MARK ";
// ret += markNumber;
// ret += ", Generator: "+this.getClass().getName().substring(this.getClass().getName().lastIndexOf('.')+1);
// ret += " ***** */";
// return emptyline()+writeString(ret)+emptyline();
}
/**
* <p>writeCommentLine.</p>
*
* @param commentline a {@link java.lang.String} object.
*/
protected void writeCommentLine(String commentline){
String tokens[] = StringUtils.tokenize(commentline, '\n');
if (tokens.length!=1)
writeComment(commentline);
else
writeString("// "+commentline);
}
/**
* <p>writeComment.</p>
*
* @param commentline a {@link java.lang.String} object.
*/
protected void writeComment(String commentline){
String tokens[] = StringUtils.tokenize(commentline, '\n');
writeString("/**");
for (int i=0; i<tokens.length; i++){
writeString(" * "+tokens[i]);
}
writeString(" */");
}
/**
* <p>startClassBody.</p>
*/
protected void startClassBody(){
ident = 1;
}
private String getFormalTypeDeclaration(ExecutableElement method){
StringBuilder formalTypeDeclaration = new StringBuilder("");
List<? extends TypeParameterElement> formalTypeParameters = method.getTypeParameters();
for (TypeParameterElement d : formalTypeParameters){
if (formalTypeDeclaration.length()>0)
formalTypeDeclaration.append(", ");
formalTypeDeclaration.append(d.toString());
List<? extends TypeMirror> bounds = d.getBounds();
if (!bounds.isEmpty())
formalTypeDeclaration.append(" extends ");
for (Iterator<? extends TypeMirror> it = bounds.iterator(); it.hasNext(); ) {
formalTypeDeclaration.append(it.next().toString());
if (it.hasNext())
formalTypeDeclaration.append(" & ");
}
}
String ret = formalTypeDeclaration.length()>0 ?
"<"+formalTypeDeclaration.toString()+">" : formalTypeDeclaration.toString();
return ret;
}
/**
* <p>getMethodDeclaration.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getMethodDeclaration(ExecutableElement method){
StringBuilder methodDecl = new StringBuilder();
//CHANGE 1.0.8 method names now return lists instead of concrete method
//methodDecl.append(getFormalTypeDeclaration(method)).append(method.getReturnType().toString()).append(" ");
methodDecl.append(getFormalTypeDeclaration(method)).append("List<?>").append(" ");
methodDecl.append(method.getSimpleName()).append("(");
Collection<? extends VariableElement> parameters = method.getParameters();
boolean first = true;
for (VariableElement p : parameters){
if (!first){
methodDecl.append(", ");
}
methodDecl.append(p.asType().toString()+" "+p.getSimpleName());
first = false;
}
methodDecl.append(")");
return methodDecl.toString();
}
/**
* <p>getInterfaceMethodDeclaration.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @param includeTransportableContext a boolean.
* @return a {@link java.lang.String} object.
*/
protected String getInterfaceMethodDeclaration(ExecutableElement method, boolean includeTransportableContext){
StringBuilder methodDecl = new StringBuilder();
//CHANGE 1.0.8 - return value is always a list.
//methodDecl.append(getFormalTypeDeclaration(method)).append(method.getReturnType().toString()).append(" ");
methodDecl.append(getFormalTypeDeclaration(method)).append("List").append(" ");
methodDecl.append(method.getSimpleName()).append("(");
Collection<? extends VariableElement> parameters = method.getParameters();
boolean first = true;
for (VariableElement p : parameters){
if (!first){
methodDecl.append(", ");
}
methodDecl.append(p.asType().toString()+" "+p.getSimpleName());
first = false;
}
if (includeTransportableContext){
//adding transportable call context for piggybacking and interceptor communication.
methodDecl.append((first ? "":", ")+"Map<?,?> __transportableCallContext");
}
methodDecl.append(")");
return methodDecl.toString();
}
/**
* <p>getAsynchInterfaceMethodDeclaration.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getAsynchInterfaceMethodDeclaration(ExecutableElement method){
StringBuilder methodDecl = new StringBuilder();
methodDecl.append(getFormalTypeDeclaration(method)).append("void").append(" ");
methodDecl.append(getAsynchMethodName(method)).append("(");
Collection<? extends VariableElement> parameters = method.getParameters();
boolean first = true;
for (VariableElement p : parameters){
if (!first){
methodDecl.append(", ");
}
methodDecl.append(p.asType().toString()+" "+p.getSimpleName());
first = false;
}
//adding call back handlers.
methodDecl.append((first ? "":", ")+"CallBackHandler ... diMeCallBackHandlers");
methodDecl.append(")");
return methodDecl.toString();
}
/**
* <p>getResourceSkeletonMethodDeclaration.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getResourceSkeletonMethodDeclaration(ExecutableElement method){
StringBuilder Element = new StringBuilder();
Element.append(getInterfaceMethodDeclaration(method, false));
if (method.getThrownTypes().size()>0){
StringBuilder exceptions = new StringBuilder();
for (TypeMirror type : method.getThrownTypes()){
if (exceptions.length()>0)
exceptions.append(", ");
exceptions.append(type.toString());
}
Element.append(" throws ").append(exceptions);
}
return Element.toString();
}
/**
* <p>getSkeletonMethodDeclaration.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getSkeletonMethodDeclaration(ExecutableElement method){
StringBuilder Element = new StringBuilder();
Element.append(getInterfaceMethodDeclaration(method, true));
if (method.getThrownTypes().size()>0){
StringBuilder exceptions = new StringBuilder();
for (TypeMirror type : method.getThrownTypes()){
if (exceptions.length()>0)
exceptions.append(", ");
exceptions.append(type.toString());
}
Element.append(" throws ").append(exceptions);
}
return Element.toString();
}
/**
* <p>getStubParametersDeclaration.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getStubParametersDeclaration(ExecutableElement method){
return getStubParametersDeclaration(method, false);
}
/**
* <p>getStubParametersDeclaration.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @param declareFinal a boolean.
* @return a {@link java.lang.String} object.
*/
protected String getStubParametersDeclaration(ExecutableElement method, boolean declareFinal){
StringBuilder ret = new StringBuilder();
Collection<? extends VariableElement> parameters = method.getParameters();
boolean first = true;
for (VariableElement p : parameters){
if (!first){
ret.append(", ");
}
ret.append((declareFinal?"final ":"")+p.asType().toString()+" "+p.getSimpleName());
first = false;
}
return ret.toString();
}
/**
* <p>getStubParametersCall.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getStubParametersCall(ExecutableElement method){
StringBuilder ret = new StringBuilder();
Collection<? extends VariableElement> parameters = method.getParameters();
boolean first = true;
for (VariableElement p : parameters){
if (!first){
ret.append(", ");
}
ret.append(p.getSimpleName());
first = false;
}
return ret.toString();
}
/**
* <p>getStubMethodDeclaration.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getStubMethodDeclaration(ExecutableElement method){
StringBuilder methodDecl = new StringBuilder();
methodDecl.append(getFormalTypeDeclaration(method)).append(method.getReturnType()).append(" ");
methodDecl.append(method.getSimpleName()).append("(");
methodDecl.append(getStubParametersDeclaration(method));
methodDecl.append(")");
if (method.getThrownTypes().size()>0){
StringBuilder exceptions = new StringBuilder();
for (TypeMirror type : method.getThrownTypes()){
if (exceptions.length()>0)
exceptions.append(", ");
exceptions.append(type.toString());
}
methodDecl.append(" throws "+exceptions.toString());
}
return methodDecl.toString();
}
/**
* <p>getStubAsynchMethodDeclaration.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getStubAsynchMethodDeclaration(ExecutableElement method){
StringBuilder methodDecl = new StringBuilder();
methodDecl.append(getFormalTypeDeclaration(method)).append(" void ");
methodDecl.append(getAsynchMethodName(method)).append("(");
String parameters = getStubParametersDeclaration(method, true);
methodDecl.append(parameters);
if (parameters.length()>0)
methodDecl.append(", ");
methodDecl.append("final CallBackHandler... diMeHandlers");
methodDecl.append(")");
// if (method.getThrownTypes().size()>0){
// StringBuilder exceptions = new StringBuilder();
// for (TypeMirror type : method.getThrownTypes()){
// if (exceptions.length()>0)
// exceptions.append(", ");
// exceptions.append(type.toString());
// }
// methodDecl.append(" throws "+exceptions.toString());
// }
return methodDecl.toString();
}
/**
* <p>getAsynchMethodName.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getAsynchMethodName(ExecutableElement method){
return "asynch"+StringUtils.capitalize(method.getSimpleName().toString());
}
/**
* <p>getInternalStubMethodDeclaration.</p>
*
* @param method a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getInternalStubMethodDeclaration(ExecutableElement method){
StringBuilder methodDecl = new StringBuilder();
methodDecl.append(getFormalTypeDeclaration(method)).append(method.getReturnType()).append(" ");
methodDecl.append(method.getSimpleName()).append("(");
String parameters = getStubParametersDeclaration(method);
methodDecl.append(parameters);
if (parameters.length()>0)
methodDecl.append(", ");
methodDecl.append(ClientSideCallContext.class.getName()+" diMeCallContext");
methodDecl.append(")");
if (method.getThrownTypes().size()>0){
StringBuilder exceptions = new StringBuilder();
for (TypeMirror type : method.getThrownTypes()){
if (exceptions.length()>0)
exceptions.append(", ");
exceptions.append(type.toString());
}
methodDecl.append(" throws "+exceptions.toString());
}
return methodDecl.toString();
}
/**
* Retrieves all methods including methods from superinterfaces.
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.util.Collection} object.
*/
protected Collection<? extends ExecutableElement> getAllDeclaredMethods(TypeElement type){
List<ExecutableElement> methods = ElementFilter.methodsIn(type.getEnclosedElements());
Types types = environment.getTypeUtils();
List<? extends TypeMirror> superinterfaces = type.getInterfaces();
for (TypeMirror it : superinterfaces){
Element element = types.asElement(it);
if (element instanceof TypeElement)
methods.addAll(getAllDeclaredMethods((TypeElement) element));
}
return methods;
}
/**
* <p>getAllDeclaredTypes.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.util.List} object.
*/
protected List<TypeElement> getAllDeclaredTypes(TypeElement type){
ArrayList<TypeElement> typesList = new ArrayList<TypeElement>();
Types types = environment.getTypeUtils();
typesList.add(type);
List<? extends TypeMirror> superinterfaces = type.getInterfaces();
for (TypeMirror it : superinterfaces){
Element element = types.asElement(it);
typesList.addAll(getAllDeclaredTypes((TypeElement) element));
}
return typesList;
}
/**
* <p>getImplementedInterfacesAsString.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getImplementedInterfacesAsString(TypeElement type){
List<TypeElement> implementedInterfaces = getAllDeclaredTypes(type);
StringBuilder interfaceAsString = new StringBuilder();
for (TypeElement in : implementedInterfaces){
if (interfaceAsString.length()>0)
interfaceAsString.append(", ");
interfaceAsString.append(in.getQualifiedName()).append(".class");
}
return interfaceAsString.toString();
}
/**
* Returns the mirror Element for a Element.
*
* @param type a {@link javax.lang.model.element.Element} object.
* @param ann a {@link java.lang.Class} object.
* @return a {@link javax.lang.model.element.AnnotationMirror} object.
*/
protected AnnotationMirror findMirror(Element type, Class<? extends Annotation> ann){
//System.out.println("-%- findMirror "+type+" ann "+ann);
List<? extends AnnotationMirror> mirros = type.getAnnotationMirrors();
for (AnnotationMirror m : mirros){
Element Element = m.getAnnotationType().asElement();
//System.out.println("--- checking "+Element.getSimpleName()+" compare with "+ann+" --> "+Element.getSimpleName().equals(ann.getSimpleName()));
if (Element.getSimpleName().toString().equals(ann.getSimpleName())){
//System.out.println("returns "+m);
return m;
}
}
//System.out.println("returns "+null);
return null;
}
/**
* <p>findMirrors.</p>
*
* @param type a {@link javax.lang.model.element.Element} object.
* @param ann a {@link java.lang.Class} object.
* @return a {@link java.util.List} object.
*/
protected List<AnnotationMirror> findMirrors(Element type, Class<? extends Annotation> ann){
//System.out.println("-%- findMirror "+type+" ann "+ann);
ArrayList<AnnotationMirror> ret = new ArrayList<AnnotationMirror>();
List<? extends AnnotationMirror> mirrors = type.getAnnotationMirrors();
for (AnnotationMirror m : mirrors){
Element element = m.getAnnotationType().asElement();
//System.out.println("--- checking "+Element.getSimpleName()+" compare with "+ann+" --> "+Element.getSimpleName().equals(ann.getSimpleName()));
if (element.getSimpleName().equals(ann.getSimpleName())){
ret.add(m);
}
}
return ret;
}
/**
* <p>findMirrorMethod.</p>
*
* @param mirror a {@link javax.lang.model.element.AnnotationMirror} object.
* @param methodName a {@link java.lang.String} object.
* @return a {@link javax.lang.model.element.ExecutableElement} object.
*/
protected ExecutableElement findMirrorMethod(AnnotationMirror mirror, String methodName){
Element executableElement = mirror.getAnnotationType().asElement();
Collection<ExecutableElement> methods = ElementFilter.methodsIn(executableElement.getEnclosedElements());
for (ExecutableElement element : methods){
if (element.getSimpleName().toString().equals(methodName))
return element;
}
return null;
}
/**
* <p>findLogWriterValue.</p>
*
* @param mirror a {@link javax.lang.model.element.AnnotationMirror} object.
* @return a {@link javax.lang.model.element.AnnotationValue} object.
*/
protected AnnotationValue findLogWriterValue(AnnotationMirror mirror){
return findMethodValue(mirror, "logWriterClazz");
}
/**
* <p>findRouterClassValue.</p>
*
* @param mirror a {@link javax.lang.model.element.AnnotationMirror} object.
* @return a {@link javax.lang.model.element.AnnotationValue} object.
*/
protected AnnotationValue findRouterClassValue(AnnotationMirror mirror){
return findMethodValue(mirror, "routerClass");
}
/**
* <p>findRouterParameterValue.</p>
*
* @param mirror a {@link javax.lang.model.element.AnnotationMirror} object.
* @return a {@link javax.lang.model.element.AnnotationValue} object.
*/
protected AnnotationValue findRouterParameterValue(AnnotationMirror mirror){
return findMethodValue(mirror, "routerParameter");
}
/**
* <p>findRouterConfigurationName.</p>
*
* @param mirror a {@link javax.lang.model.element.AnnotationMirror} object.
* @return a {@link javax.lang.model.element.AnnotationValue} object.
*/
protected AnnotationValue findRouterConfigurationName(AnnotationMirror mirror){
return findMethodValue(mirror, "configurationName");
}
/**
* <p>findMethodValue.</p>
*
* @param mirror a {@link javax.lang.model.element.AnnotationMirror} object.
* @param methodName a {@link java.lang.String} object.
* @return a {@link javax.lang.model.element.AnnotationValue} object.
*/
protected AnnotationValue findMethodValue(AnnotationMirror mirror, String methodName){
//System.out.println("-- Called findMethodValue on "+methodName+" and "+mirror);
ExecutableElement method = findMirrorMethod(mirror, methodName);
Map<? extends ExecutableElement, ? extends AnnotationValue> values = mirror.getElementValues();
//System.out.println("-- values --: "+values);
AnnotationValue mirrorMethodValue = values.get(method);
return mirrorMethodValue;
}
/**
* Concurrency control annotation - representation helper class at gen-time.
* @author lrosenberg
*
*/
protected static class TranslatedCCAnnotation extends TranslatedAnnotation{
public TranslatedCCAnnotation(String aStrategyClass, String aParameter){
super(aStrategyClass, aParameter, ccOrders.incrementAndGet());
}
}
/**
* Router annotation - representation helper class at gen-time.
* @author lrosenberg
*
*/
protected static class TranslatedRouterAnnotation extends TranslatedAnnotation{
public TranslatedRouterAnnotation(String aStrategyClass, String aParameter, String configurationName){
super(aStrategyClass, aParameter, routerOrders.incrementAndGet());
setConfigurationName(configurationName);
}
}
/**
* <p>findConcurrencyControlAnnotation.</p>
*
* @param type a {@link javax.lang.model.element.Element} object.
* @return a {@link org.distributeme.generator.AbstractGenerator.TranslatedCCAnnotation} object.
*/
protected TranslatedCCAnnotation findConcurrencyControlAnnotation(Element type){
//try all shortcuts first.
Annotation ann;
ann = type.getAnnotation(ConcurrencyControlServerSideLimit.class);
if (ann!=null){
String configName = ((ConcurrencyControlServerSideLimit)ann).configurationName();
if (configName!=null && configName.length()>0)
return new TranslatedCCAnnotation("org.distributeme.core.concurrencycontrol.ConfigurationBasedConcurrencyControlStrategy", configName);
return new TranslatedCCAnnotation("org.distributeme.core.concurrencycontrol.ConstantBasedConcurrencyControlStrategy", "0,"+((ConcurrencyControlServerSideLimit)ann).value());
}
ann = type.getAnnotation(ConcurrencyControlClientSideLimit.class);
if (ann!=null){
String configName = ((ConcurrencyControlClientSideLimit)ann).configurationName();
if (configName!=null && configName.length()>0)
return new TranslatedCCAnnotation("org.distributeme.core.concurrencycontrol.ConfigurationBasedConcurrencyControlStrategy", configName);
return new TranslatedCCAnnotation("org.distributeme.core.concurrencycontrol.ConstantBasedConcurrencyControlStrategy", ""+((ConcurrencyControlClientSideLimit)ann).value()+",0");
}
ann = type.getAnnotation(ConcurrencyControlLimit.class);
if (ann!=null){
String configName = ((ConcurrencyControlLimit)ann).configurationName();
if (configName!=null && configName.length()>0)
return new TranslatedCCAnnotation("org.distributeme.core.concurrencycontrol.ConfigurationBasedConcurrencyControlStrategy", configName);
return new TranslatedCCAnnotation("org.distributeme.core.concurrencycontrol.ConstantBasedConcurrencyControlStrategy", ""+((ConcurrencyControlLimit)ann).client()+","+((ConcurrencyControlLimit)ann).server());
}
return null;
}
/**
* <p>writeRouterDeclarations.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.util.List} object.
*/
protected List<TranslatedRouterAnnotation> writeRouterDeclarations(TypeElement type){
List<TranslatedRouterAnnotation> ret = new ArrayList<AbstractGenerator.TranslatedRouterAnnotation>();
Collection<? extends ExecutableElement> methods = getAllDeclaredMethods(type);
writeCommentLine("ROUTER DECL V2");
AnnotationMirror clazzWideRoute = findMirror(type, Route.class);
if (clazzWideRoute!=null){
writeCommentLine("Class wide router ");
AnnotationValue configurationNameValue = findRouterConfigurationName(clazzWideRoute);
TranslatedRouterAnnotation tra = new TranslatedRouterAnnotation(""+findRouterClassValue(clazzWideRoute).getValue(),
""+findRouterParameterValue(clazzWideRoute).getValue(),
configurationNameValue == null ? "":""+configurationNameValue.getValue()
);
writeStatement("private final "+Router.class.getName() + " clazzWideRouter = createRouterInstance"+tra.getOrder()+"()");
ret.add(tra);
}else{
writeCommentLine("No class-wide-router set, skipping.");
}
emptyline();
writeCommentLine("Method wide routers if applicable ");
for (ExecutableElement method : methods){
AnnotationMirror methodRoute = findMirror(method, Route.class);
if (methodRoute!=null){
//System.out.println("Will write "+Router.class.getName()+" "+getMethodRouterName(method));
AnnotationValue routerParameterValue = findRouterParameterValue(methodRoute);
AnnotationValue configurationNameValue = findRouterConfigurationName(methodRoute);
TranslatedRouterAnnotation tra = new TranslatedRouterAnnotation(""+findRouterClassValue(methodRoute).getValue(),
routerParameterValue == null ? "":""+routerParameterValue.getValue(),
configurationNameValue == null ? "":""+configurationNameValue.getValue()
);
writeStatement("private final "+Router.class.getName()+" "+getMethodRouterName(method) +" = createRouterInstance"+tra.getOrder()+"()");
ret.add(tra);
}
}
writeCommentLine("Method wide routers END ");
emptyline();
//AnnotationMirror clazzWideCCStrategyAnnotation = findMirror(type, ConcurrencyControl.class);
// TranslatedCCAnnotation clazzWideCCStrategyAnnotation = findConcurrencyControlAnnotation(type);
// if (clazzWideCCStrategyAnnotation!=null){
// writeStatement("private ConcurrencyControlStrategy clazzWideCCStrategy = createConcurrencyControlStrategy"+clazzWideCCStrategyAnnotation.getOrder()+"()");
// ret.add(clazzWideCCStrategyAnnotation);
// }else{
// writeStatement("private ConcurrencyControlStrategy clazzWideCCStrategy = "+Defaults.class.getSimpleName()+".getDefaultConcurrencyControlStrategy()");
// }
// emptyline();
//
// for (ExecutableElement method : methods){
// TranslatedCCAnnotation methodCCStrategyAnnotation = findConcurrencyControlAnnotation(method);
// if (methodCCStrategyAnnotation != null){
// writeStatement("private ConcurrencyControlStrategy "+getCCStrategyVariableName(method)+" = createConcurrencyControlStrategy"+methodCCStrategyAnnotation.getOrder()+"()");
// ret.add(methodCCStrategyAnnotation);
// }else{
// writeStatement("private ConcurrencyControlStrategy "+getCCStrategyVariableName(method)+" = clazzWideCCStrategy");
// }
// }
// writeCommentLine("CONCURRENCY CONTROL end");
// emptyline();
writeCommentLine("ROUTER DECL V2 end");
return ret;
}
/**
* <p>writeConcurrencyControlDeclarations.</p>
*
* @param type a {@link javax.lang.model.element.TypeElement} object.
* @return a {@link java.util.List} object.
*/
protected List<TranslatedCCAnnotation> writeConcurrencyControlDeclarations(TypeElement type){
List<TranslatedCCAnnotation> ret = new ArrayList<AbstractGenerator.TranslatedCCAnnotation>();
Collection<? extends ExecutableElement> methods = getAllDeclaredMethods(type);
writeCommentLine("CONCURRENCY CONTROL");
writeCommentLine("Class wide concurrency control strategy ");
//AnnotationMirror clazzWideCCStrategyAnnotation = findMirror(type, ConcurrencyControl.class);
TranslatedCCAnnotation clazzWideCCStrategyAnnotation = findConcurrencyControlAnnotation(type);
if (clazzWideCCStrategyAnnotation!=null){
writeStatement("private ConcurrencyControlStrategy clazzWideCCStrategy = createConcurrencyControlStrategy"+clazzWideCCStrategyAnnotation.getOrder()+"()");
ret.add(clazzWideCCStrategyAnnotation);
}else{
writeStatement("private ConcurrencyControlStrategy clazzWideCCStrategy = "+Defaults.class.getSimpleName()+".getDefaultConcurrencyControlStrategy()");
}
emptyline();
for (ExecutableElement method : methods){
TranslatedCCAnnotation methodCCStrategyAnnotation = findConcurrencyControlAnnotation(method);
if (methodCCStrategyAnnotation != null){
writeStatement("private ConcurrencyControlStrategy "+getCCStrategyVariableName(method)+" = createConcurrencyControlStrategy"+methodCCStrategyAnnotation.getOrder()+"()");
ret.add(methodCCStrategyAnnotation);
}else{
writeStatement("private ConcurrencyControlStrategy "+getCCStrategyVariableName(method)+" = clazzWideCCStrategy");
}
}
writeCommentLine("CONCURRENCY CONTROL end");
emptyline();
return ret;
}
private StringBuilder getParameterizedVariableName(ExecutableElement Element){
StringBuilder ret = new StringBuilder();
for (VariableElement pd : Element.getParameters()){
ret.append('_');
ret.append(stripStrategyVariableName(pd.asType().toString()));
//ret.append(pd.getType().getClass().getSimpleName());
ret.append(pd.getSimpleName());
}
return ret;
}
/**
* Returns the name of the failing strategy variable for a method.
*
* @param Element a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getFailingStrategyVariableName(ExecutableElement Element){
StringBuilder ret = new StringBuilder(Element.getSimpleName()).append("FailingStrategy");
ret.append(getParameterizedVariableName(Element));
return ret.toString();
}
/**
* Returns the name for concurrency control strategy variable
*
* @param Element a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getCCStrategyVariableName(ExecutableElement Element){
StringBuilder ret = new StringBuilder(Element.getSimpleName()).append("CCStrategy");
ret.append(getParameterizedVariableName(Element));
return ret.toString();
}
//included <> as backup in case we have generic types in types (List<Set<String>>).
/**
* Chars which should be removed from names of variables.
*/
private static char[] toRemove = {'.', '[', ']', '<', '>'};
private String stripStrategyVariableName(String toStrip){
String ret = StringUtils.removeTag(toStrip, "");
ret = StringUtils.removeChars(ret, toRemove);
return ret;
}
/**
* <p>writeConcurrencyControlCreationMethod.</p>
*
* @param cca a {@link org.distributeme.generator.AbstractGenerator.TranslatedCCAnnotation} object.
*/
protected void writeConcurrencyControlCreationMethod(TranslatedCCAnnotation cca){
writeString("private ConcurrencyControlStrategy createConcurrencyControlStrategy"+cca.getOrder()+"(){");
increaseIdent();
writeStatement("ConcurrencyControlStrategy strat = new "+cca.getStrategyClass()+"()");
writeStatement("strat.customize("+quote(cca.getParameter())+")");
writeStatement("return strat");
closeBlock();
}
/**
* <p>writeRouterCreationMethod.</p>
*
* @param serviceIdCall a {@link java.lang.String} object.
* @param tra a {@link org.distributeme.generator.AbstractGenerator.TranslatedRouterAnnotation} object.
*/
protected void writeRouterCreationMethod(String serviceIdCall, TranslatedRouterAnnotation tra){
writeString("private "+Router.class.getName()+" createRouterInstance"+tra.getOrder()+"(){");
increaseIdent();
writeStatement(Router.class.getName()+" router = new "+tra.getStrategyClass()+"()");
if (tra.getConfigurationName()!=null && tra.getConfigurationName().length()>0){
writeStatement("((org.distributeme.core.routing.ConfigurableRouter)router).setConfigurationName("+serviceIdCall+ ", " +quote(tra.getConfigurationName())+")");
}else {
writeStatement("router.customize("+serviceIdCall+ ", " + quote(tra.getParameter()) + ")");
}
writeStatement("return router");
closeBlock();
}
/**
* <p>interceptionPhaseToMethod.</p>
*
* @param phase a {@link org.distributeme.core.interceptor.InterceptionPhase} object.
* @return a {@link java.lang.String} object.
*/
protected String interceptionPhaseToMethod(InterceptionPhase phase){
switch(phase){
case BEFORE_SERVANT_CALL:
return "beforeServantCall";
case BEFORE_SERVICE_CALL:
return "beforeServiceCall";
case AFTER_SERVICE_CALL:
return "afterServiceCall";
case AFTER_SERVANT_CALL:
return "afterServantCall";
default:
throw new IllegalArgumentException("Unsupported interception phase");
}
}
/**
* Returns true if the method has no return value.
*
* @param decl a {@link javax.lang.model.element.ExecutableElement} object.
* @return a boolean.
*/
protected boolean isVoidReturn(ExecutableElement decl){
return decl.getReturnType().toString().equals("void");
}
/**
* <p>getMethodRouterName.</p>
*
* @param Element a {@link javax.lang.model.element.ExecutableElement} object.
* @return a {@link java.lang.String} object.
*/
protected String getMethodRouterName(ExecutableElement Element){
return Element.getSimpleName()+"Router";
}
}