Commit b251269c authored by Stefan Schuhbaeck's avatar Stefan Schuhbaeck
Browse files

add VadereAnnotation Module

parent 3143a48d
......@@ -10,8 +10,8 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>annotation-processing</artifactId>
<name>Annotation Processing</name>
<artifactId>annotation</artifactId>
<name>Vadere Annotation</name>
<dependencies>
......@@ -38,7 +38,6 @@
<directory>resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>testResources</directory>
......@@ -50,9 +49,9 @@
</excludes>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler.version}</version>
<configuration>
......@@ -61,5 +60,7 @@
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package org.vadere.annotation.factories;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;
public abstract class BaseFactoryProcessor extends AbstractProcessor {
protected String factoryType;
protected String factoryClassName;
protected String factoryPackage;
protected String[] factoryImports;
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations){
//only no abstract classes...
Set<? extends Element> annotatedElements =
roundEnv.getElementsAnnotatedWith(annotation)
.stream()
.filter(e -> e.getKind().isClass()
&& !e.getKind().equals(ElementKind.ENUM)
&& !e.getModifiers().contains(Modifier.ABSTRACT)
)
.collect(Collectors.toSet());
if (annotatedElements.isEmpty())
continue;
FactoryType factoryType = annotation.getAnnotation(FactoryType.class);
assert factoryType != null;
this.factoryType = factoryType.factoryType();
this.factoryClassName = factoryType.factoryName();
this.factoryPackage = factoryType.factoryPackage();
this.factoryImports = factoryType.factoryImports();
try {
writeFactory(annotatedElements);
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
protected abstract String label(Element element);
protected abstract String descr(Element element);
protected String name(Element e){
return e.getSimpleName().toString();
}
protected abstract void addImports(Set<? extends Element> elements, PrintWriter writer);
protected abstract void addLast(Set<? extends Element> elements, PrintWriter writer);
private void writeFactory(Set<? extends Element> elements) throws IOException {
JavaFileObject jFile = processingEnv.getFiler().createSourceFile(factoryClassName);
try (PrintWriter out = new PrintWriter(jFile.openWriter())) {
out.append("package ").append(factoryPackage).append(";").println();
out.println();
out.println("import org.vadere.util.factory.BaseFactory;");
for (String factoryImport : factoryImports) {
out.append("import ").append(factoryImport).println(";");
}
out.println();
for(Element e : elements){
TypeElement p = (TypeElement)e;
out.append("import ").append(p.getQualifiedName()).println(";");
}
out.println();
//add additional import defined by subclass
addImports(elements, out);
out.println();
out.println();
out.append("public class ").append(factoryClassName).append(" extends BaseFactory<").append(factoryType).append("> {").println();
out.println();
Util.createSingletone(factoryClassName, out);
out.println();
// private constructor.
out.append(" private ").append(factoryClassName).append("(){").println();
out.println("// add Members to Factory");
for (Element e : elements) {
out.append(" addMember(");
out.append(e.getSimpleName().toString()).append(".class, ");
out.append("this::").append("get").append(name(e)).append(", ");
out.append(Util.quote(label(e))).append(", ");
out.append(Util.quote(descr(e))).append(");");
out.println();
}
out.println(" }");
out.println();
out.println();
out.println("// Getters");
for (Element element : elements) {
TypeElement p = (TypeElement)element;
out.append(" public ").append(p.getSimpleName())
.append(" get").append(p.getSimpleName()).append("()").println("{");
out.append(" return new ").append(p.getSimpleName()).println("();");
out.append(" }").println();
out.println();
}
out.println("// additional methods");
//add additional methods defined by subclass
addLast(elements, out);
out.println();
out.println("}");
}
}
}
package org.vadere.annotation.factories.processor;
package org.vadere.annotation.factories;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@FactoryType(
factoryType = "DataProcessor<?, ?>",
factoryImports = {
"org.vadere.simulator.projects.dataprocessing.processor.DataProcessor"
},
factoryName = "DataProcessorFactoryXX",
factoryPackage = "org.vadere.simulator.projects.dataprocessing.processor"
)
public @interface DataProcessorClass {
String name();
String label() default "";
String description() default "";
}
package org.vadere.annotation.factories;
import com.google.auto.service.AutoService;
import java.io.PrintWriter;
import java.util.Set;
import javax.annotation.processing.Processor;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
@SupportedAnnotationTypes("org.vadere.annotation.factories.DataProcessorClass")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class DataProcessorFactoryProcessor extends BaseFactoryProcessor {
protected String label(Element element){
DataProcessorClass dataProcessorClass = element.getAnnotation(DataProcessorClass.class);
String label = dataProcessorClass.label();
return label.isEmpty() ? element.getSimpleName().toString() : label;
}
protected String descr(Element element){
DataProcessorClass dataProcessorClass = element.getAnnotation(DataProcessorClass.class);
return dataProcessorClass.description();
}
@Override
protected void addImports(Set<? extends Element> elements, PrintWriter writer) {
writer.println("import org.vadere.simulator.projects.dataprocessing.store.DataProcessorStore;");
}
@Override
protected void addLast(Set<? extends Element> elements, PrintWriter writer) {
writer.println(" public DataProcessor<?, ?> createDataProcessor(DataProcessorStore dataProcessorStore) {");
writer.println(" DataProcessor<?, ?> processor = getInstanceOf(dataProcessorStore.getType());");
writer.println(" processor.setId(dataProcessorStore.getId());");
writer.println(" processor.setAttributes(dataProcessorStore.getAttributes());");
writer.println(" return processor;");
writer.println(" }");
writer.println();
writer.println();
writer.println(" public DataProcessor<?, ?> createDataProcessor(String type) {");
writer.println(" DataProcessorStore dataProcessorStore = new DataProcessorStore();");
writer.println(" dataProcessorStore.setType(type);");
writer.println(" DataProcessor<?, ?> processor = getInstanceOf(dataProcessorStore.getType());");
writer.println(" processor.setId(dataProcessorStore.getId());");
writer.println(" processor.setAttributes(dataProcessorStore.getAttributes());");
writer.println(" return processor;");
writer.println(" }");
writer.println();
writer.println(" public DataProcessor<?, ?> createDataProcessor(Class type) {");
writer.println(" return createDataProcessor(type.getCanonicalName());");
writer.println(" }");
}
}
package org.vadere.annotation.factories;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.ANNOTATION_TYPE)
public @interface FactoryType {
String factoryType();
String[] factoryImports();
String factoryName();
String factoryPackage();
}
package org.vadere.annotation.factories;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@FactoryType(
factoryType = "OutputFile<? extends DataKey<?>>",
factoryImports = {
"org.vadere.simulator.projects.dataprocessing.outputfile.OutputFile",
"org.vadere.simulator.projects.dataprocessing.datakey.DataKey"
},
factoryName = "OutputFileFactoryXX",
factoryPackage = "org.vadere.simulator.projects.dataprocessing.outputfile"
)
public @interface OutputFileClass {
String label() default "";
String description() default "";
}
package org.vadere.annotation.factories;
import com.google.auto.service.AutoService;
import java.io.PrintWriter;
import java.util.Set;
import javax.annotation.processing.Processor;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
@SupportedAnnotationTypes("org.vadere.annotation.factories.OutputFileClass")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class OutputFileFactoryProcessor extends BaseFactoryProcessor {
protected String label(Element element){
OutputFileClass dataProcessorClass = element.getAnnotation(OutputFileClass.class);
String label = dataProcessorClass.label();
return label.isEmpty() ? element.getSimpleName().toString() : label;
}
protected String descr(Element element){
OutputFileClass dataProcessorClass = element.getAnnotation(OutputFileClass.class);
return dataProcessorClass.description();
}
@Override
protected void addImports(Set<? extends Element> elements, PrintWriter writer) {
writer.println("import org.vadere.simulator.projects.dataprocessing.datakey.DataKey;");
writer.println("import org.vadere.simulator.projects.dataprocessing.datakey.OutputFileMap;");
writer.println("import org.vadere.simulator.projects.dataprocessing.store.OutputFileStore;");
writer.println("import java.util.Arrays;");
}
@Override
protected void addLast(Set<? extends Element> elements, PrintWriter writer) {
writer.println(" public OutputFile<?> createOutputfile(OutputFileStore fileStore) {");
writer.println(" OutputFile<?> file = getInstanceOf(fileStore.getType());");
writer.println(" file.setRelativeFileName(fileStore.getFilename());");
writer.println(" file.setProcessorIds(fileStore.getProcessors());");
writer.println(" file.setSeparator(fileStore.getSeparator());");
writer.println(" return file;");
writer.println(" }");
writer.println();
writer.println(" public OutputFile<?> createDefaultOutputfile() {");
writer.println(" OutputFileStore fileStore = new OutputFileStore();");
writer.println(" OutputFile<?> file = getInstanceOf(fileStore.getType());");
writer.println(" file.setSeparator(fileStore.getSeparator());");
writer.println(" return file;");
writer.println(" }");
writer.println();
writer.println(" public OutputFile<?> createOutputfile(String type) {");
writer.println(" OutputFileStore fileStore = new OutputFileStore();");
writer.println(" fileStore.setType(type);");
writer.println(" OutputFile<?> file = getInstanceOf(fileStore.getType());");
writer.println(" file.setSeparator(fileStore.getSeparator());");
writer.println(" return file;");
writer.println(" }");
writer.println();
writer.println(" public OutputFile<?> createOutputfile(Class type) {");
writer.println(" return createOutputfile(type.getCanonicalName());");
writer.println(" }");
writer.println();
writer.println(" public OutputFile<?> createOutputfile(Class type, Integer... processorsIds) {");
writer.println(" OutputFile<?> file = createOutputfile(type.getCanonicalName());");
writer.println(" file.setProcessorIds(Arrays.asList(processorsIds));");
writer.println(" return file;");
writer.println(" }");
writer.println();
writer.println(" public OutputFile<?> createDefaultOutputfileByDataKey(Class<? extends DataKey<?>> keyType, Integer... processorsIds) {");
writer.println(" OutputFile<?> file = createDefaultOutputfileByDataKey(keyType);");
writer.println(" file.setProcessorIds(Arrays.asList(processorsIds));");
writer.println(" return file;");
writer.println(" }");
writer.println();
writer.println(" public OutputFile<?> createDefaultOutputfileByDataKey(Class<? extends DataKey<?>> keyType) {");
writer.println();
writer.println(" OutputFileMap outputFileMap = keyType.getAnnotation(OutputFileMap.class);");
writer.println(" return createOutputfile(outputFileMap.outputFileClass());");
writer.println(" }");
}
}
package org.vadere.annotation.factories;
import java.io.PrintWriter;
public class Util {
private static final String QUOTE = "\"";
public static void createSingletone(final String instanceType, PrintWriter writer){
writer.append(" private static ").append(instanceType).append(" instance;").println();
writer.println();
writer.println(" //performance threadsafe Singletone. Sync block will only be used once");
writer.append(" public static ").append(instanceType).append(" instance(){").println();
writer.println(" if(instance == null){");
writer.append(" synchronized (").append(instanceType).append(".class){").println();
writer.println(" if(instance == null){");
writer.append(" instance = new ").append(instanceType).append("();").println();
writer.println(" }");
writer.println(" }");
writer.println(" }");
writer.println(" return instance;");
writer.println(" }");
writer.println();
}
public static String quote(final String data){
return QUOTE + data + QUOTE;
}
}
......@@ -59,7 +59,7 @@
<annotationProcessorPaths>
<path>
<groupId>org.vadere</groupId>
<artifactId>annotation-processing</artifactId>
<artifactId>annotation</artifactId>
<version>0.1-SNAPSHOT</version>
</path>
</annotationProcessorPaths>
......@@ -179,7 +179,7 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>annotation-processing</artifactId>
<artifactId>annotation</artifactId>
<version>${project.version}</version>
</dependency>
......
package org.vadere.util.factory;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public abstract class BaseFactory<T> {
protected HashMap<String, FactoryObject<T>> supplierMap;
public BaseFactory(){
supplierMap = new HashMap<>();
}
public void addMember(Class clazz, Supplier<T> supplier){
addMember(clazz, supplier, clazz.getName());
}
public void addMember(Class clazz, Supplier<T> supplier, String label){
addMember(clazz, supplier,label, "");
}
public void addMember(Class clazz, Supplier<T> supplier, String label, String description){
supplierMap.put(clazz.getCanonicalName(), new FactoryObject<>(clazz, label, description, supplier));
}
public Map<String, String> getLabelMap() {
return supplierMap.entrySet().stream().collect(
Collectors.toMap(entry -> entry.getValue().getLabel(), entry-> entry.getKey()));
}
public T getInstanceOf(String clazz){
Optional<FactoryObject<T>> opt =Optional.ofNullable(supplierMap.get(clazz));
return opt.isPresent() ? opt.get().getSupplier().get() : null;
}
public T getInstanceOf(Class clazz){
return getInstanceOf(clazz.getCanonicalName());
}
public Supplier<T> getSupplierOf(String clazz){
Optional<FactoryObject<T>> opt =Optional.ofNullable(supplierMap.get(clazz));
return opt.isPresent() ? opt.get().getSupplier() : null;
}
public Supplier<T> getSupplierOf(Class clazz){
return getSupplierOf(clazz.getCanonicalName());
}
}
package org.vadere.util.factory;
import java.util.function.Supplier;
public class FactoryObject<T> {
private final Class clazz;
private final String label;
private final String description;
private Supplier<T> supplier;
public FactoryObject(Class clazz, String label, String description, Supplier<T> supplier){
this.clazz = clazz;
this.label = label;
this.description = description;
this.supplier = supplier;
}
public String getLabel() {
return label;
}
//todo: this should be locale with Messages.
public String getDescription() {
return description;
}
public Supplier<T> getSupplier() {
return supplier;
}
}
package org.vadere.annotation.factories.processor;
import com.google.auto.service.AutoService;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;
@SupportedAnnotationTypes("org.vadere.annotation.factories.processor.*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class DataProcessorFactoryProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations){
//only no abstract classes...
Set<? extends Element> annotatedElements =
roundEnv.getElementsAnnotatedWith(annotation)
.stream()
.filter(e -> e.getKind().isClass()
&& !e.getKind().equals(ElementKind.ENUM)
&& !e.getModifiers().contains(Modifier.ABSTRACT)
)
.collect(Collectors.toSet());
if (annotatedElements.isEmpty())
continue;
try {
writeDataProcessorFactory("org.vadere.simulator.projects.dataprocessing.processor.DataProcessorFactory3", annotatedElements);
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
private void writeDataProcessorFactory2(String className, Set<? extends Element> dataProcessors) throws IOException {
String packageName = null;
int lastDot = className.lastIndexOf('.');
if (lastDot > 0)
packageName = className.substring(0, lastDot);