summaryrefslogtreecommitdiff
path: root/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java
diff options
context:
space:
mode:
Diffstat (limited to 'container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java')
-rw-r--r--container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java182
1 files changed, 182 insertions, 0 deletions
diff --git a/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java
new file mode 100644
index 0000000..f1f3bc5
--- /dev/null
+++ b/container-compiler-plugin/src/main/java/io/trygvis/container/compiler/TransactionalHandler.java
@@ -0,0 +1,182 @@
+package io.trygvis.container.compiler;
+
+import io.trygvis.container.compiler.model.ClassG;
+import io.trygvis.container.compiler.model.FieldRef;
+import io.trygvis.container.compiler.model.ParameterRef;
+import io.trygvis.container.compiler.model.Parameters;
+import io.trygvis.container.compiler.model.TypeRef;
+import io.trygvis.container.tx.PlatformTransactionManager;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.JavaFileObject;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import static javax.lang.model.util.ElementFilter.constructorsIn;
+import static org.springframework.util.StringUtils.collectionToDelimitedString;
+
+public class TransactionalHandler {
+
+ private final ProcessingEnvironment processingEnv;
+ private final Elements elements;
+ private final Types types;
+
+ public TransactionalHandler(ProcessingEnvironment processingEnv) {
+ this.processingEnv = processingEnv;
+ this.elements = processingEnv.getElementUtils();
+ this.types = processingEnv.getTypeUtils();
+ }
+
+ public void processTransactional(TypeElement element) throws IOException {
+ Name targetClassName = element.getSimpleName();
+ System.out.println("Processing @Transactional " + targetClassName);
+
+ Transactional transactional = element.getAnnotation(Transactional.class);
+
+ String p = elements.getPackageOf(element).getQualifiedName().toString();
+
+ String className = targetClassName + "_Transactional";
+
+ JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(p + "." + className, element);
+
+ try (PrintWriter w = new PrintWriter(sourceFile.openWriter())) {
+ ClassG g = new ClassG(p, className, targetClassName.toString());
+// writer.println("package " + p + ";");
+// writer.println();
+// writer.println("import io.trygvis.container.tx.PlatformTransactionManager;");
+// writer.println();
+// writer.println("public class " + className + " extends " + targetClassName + " {");
+// writer.println(" private final PlatformTransactionManager transactionManager;");
+// writer.println();
+
+// TypeRef platformTransactionManager = g.addImport(PlatformTransactionManager.class);
+ FieldRef transactionManager = g.addField(PlatformTransactionManager.class, "transactionManager");
+
+ for (ExecutableElement constructor : constructorsIn(elements.getAllMembers(element))) {
+ if (!constructor.getModifiers().contains(Modifier.PUBLIC)) {
+ continue;
+ }
+
+ constructor(g, constructor, transactionManager);
+ }
+
+// System.out.println("elements.getTypeElement(\"Object\") = " + elements.getTypeElement("java.lang.Object"));
+ Name javaLangObjectName = elements.getTypeElement("java.lang.Object").getQualifiedName();
+
+ for (Element e : elements.getAllMembers(element)) {
+ if (!(e instanceof ExecutableElement)) {
+ continue;
+ }
+
+ ExecutableElement ee = (ExecutableElement) e;
+
+ TypeElement enclosingElement = (TypeElement) ee.getEnclosingElement();
+
+ if (enclosingElement.getQualifiedName().equals(javaLangObjectName)) {
+ continue;
+ }
+
+ if (ee.getSimpleName().toString().equals("<init>")) {
+ continue;
+ }
+
+// System.out.println("ee.getSimpleName() = " + ee.getSimpleName());
+// System.out.println("ee.getEnclosingElement() = " + enclosingElement);
+// System.out.println("ee.getEnclosingElement().getQualifiedName() = " + enclosingElement.getQualifiedName());
+// System.out.println("ee.getEnclosingElement().asType().getKind().getDeclaringClass() = " + enclosingElement.asType().getKind().getDeclaringClass());
+
+ TypeMirror returnTypeMirror = ee.getReturnType();
+
+ TypeKind kind = returnTypeMirror.getKind();
+
+ boolean isVoid = kind == TypeKind.VOID;
+ TypeRef returnType = isVoid ? TypeRef.VOID : g.addImport(returnTypeMirror);
+// String returnString;
+// if (isVoid) {
+// returnString = "void";
+// } else {
+// returnString = returnTypeMirror.toString();
+// }
+
+ List<ParameterRef> parameters = new ArrayList<>();
+ List<String> arguments = new ArrayList<>();
+ for (VariableElement ve : ee.getParameters()) {
+// parameters.add("final " + ve.asType().toString() + " " + ve.getSimpleName().toString());
+ TypeRef k = g.addImport(ve.asType());
+ parameters.add(new ParameterRef(k, ve.getSimpleName().toString()));
+ arguments.add(ve.getSimpleName().toString());
+ }
+
+ List<String> body = new ArrayList<>();
+
+// writer.println();
+// writer.println(" public " + returnString + " " + ee.getSimpleName() + "(" + collectionToDelimitedString(parameters, ", ") + ") {");
+
+ body.add((isVoid ? "" : "return ") + "transactionManager.doInTransaction(");
+ body.add(" PlatformTransactionManager.TransactionIsolation.ISOLATION_" + transactional.isolation() + ",");
+ body.add(" PlatformTransactionManager.TransactionPropagation.PROPAGATION_" + transactional.propagation() + ",");
+ body.add(" new PlatformTransactionManager.TransactionTemplate<" + (isVoid ? "Object" : returnTypeMirror) + ">() {");
+ body.add(" @Override");
+ body.add(" public " + (isVoid ? "Object" : returnTypeMirror) + " doInTransaction() {");
+ String targetInvocation = className + ".super." + ee.getSimpleName() + "(" + collectionToDelimitedString(arguments, ", ") + ");";
+
+ if (isVoid) {
+ body.add(" " + targetInvocation);
+ body.add(" return null;");
+ } else {
+ body.add(" return " + targetInvocation);
+ }
+
+ body.add(" }");
+ body.add(" });");
+
+ g.addMethod(body, returnType, ee.getSimpleName().toString(), parameters.toArray(new ParameterRef[arguments.size()]));
+// elements.printElements(new PrintWriter(System.out), ee);
+ }
+// writer.println("}");
+ g.write(w);
+ }
+ }
+
+ private void constructor(ClassG g, ExecutableElement constructor, FieldRef platformTransactionManager) {
+ Parameters parameters = new Parameters();
+ List<String> goesToSuper = new ArrayList<>();
+
+ TypeRef k = g.addImport(PlatformTransactionManager.class);
+ ParameterRef transactionManager = parameters.addParameter(k, "transactionManager");
+
+ for (VariableElement p : constructor.getParameters()) {
+// parameters.add(p.asType().toString() + " " + p.getSimpleName().toString());
+// arguments.add(p.getSimpleName().toString());
+ k = g.addImport(p.asType());
+ String name = p.getSimpleName().toString();
+ parameters.addParameter(k, name);
+ goesToSuper.add(name);
+ }
+
+// String params = parameters.size() == 0 ? "" : ", " + collectionToDelimitedString(parameters, ", ");
+
+ List<String> body = new ArrayList<>();
+ body.add("super(" + collectionToDelimitedString(goesToSuper, ", ") + ");");
+ body.add("this." + platformTransactionManager.name + " = " + transactionManager.name + ";");
+ g.addConstructor(parameters, body);
+
+// writer.println(" public " + className + "(PlatformTransactionManager _transactionManager_" + params + ") {");
+// writer.println(" super(" + collectionToDelimitedString(arguments, ", ") + ");");
+// writer.println(" this.transactionManager = _transactionManager_;");
+// writer.println(" }");
+ }
+}