diff --git a/common/client/pom.xml b/common/client/pom.xml index c67339949..d8e3bafd3 100644 --- a/common/client/pom.xml +++ b/common/client/pom.xml @@ -8,10 +8,38 @@ zingg-common-client jar + + zingg + zingg-common-py + ${zingg.version} + javax.mail mail 1.4 + + + + + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.source} + true + + + + zingg.common.py.processors.PythonClassProcessor + + + zingg.common.py.processors.PythonMethodProcessor + + + + + + diff --git a/common/client/src/main/java/zingg/common/client/pipe/Pipe.java b/common/client/src/main/java/zingg/common/client/pipe/Pipe.java index 7a4f8ff88..99e80c9cc 100644 --- a/common/client/src/main/java/zingg/common/client/pipe/Pipe.java +++ b/common/client/src/main/java/zingg/common/client/pipe/Pipe.java @@ -11,13 +11,16 @@ import zingg.common.client.ZFrame; import zingg.common.client.util.StringRedactor; +import zingg.common.py.annotations.PythonClass; +import zingg.common.py.annotations.PythonMethod; + /**Actual pipe def in the args. One pipe can be used at multiple places with different tables, locations, queries etc * * @author sgoyal * */ - +@PythonClass @JsonInclude(Include.NON_NULL) public class Pipe implements Serializable{ // St:StructType, Sv:SaveMode @@ -57,12 +60,12 @@ public void setSchema(String schema) { this.schema = schema; } - + @PythonMethod public String getName() { return name; } - + @PythonMethod @JsonValue public void setName(String name) { this.name = name; diff --git a/common/pom.xml b/common/pom.xml index 23dd19064..c50c2b037 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -12,5 +12,6 @@ infra core client + py diff --git a/common/py/pom.xml b/common/py/pom.xml new file mode 100644 index 000000000..bde63932b --- /dev/null +++ b/common/py/pom.xml @@ -0,0 +1,10 @@ + + 4.0.0 + + zingg + zingg-common + ${zingg.version} + + zingg-common-py + \ No newline at end of file diff --git a/common/py/src/main/java/zingg/common/py/annotations/PythonClass.java b/common/py/src/main/java/zingg/common/py/annotations/PythonClass.java new file mode 100644 index 000000000..0d3bf21a5 --- /dev/null +++ b/common/py/src/main/java/zingg/common/py/annotations/PythonClass.java @@ -0,0 +1,9 @@ +package zingg.common.py.annotations; + +import javax.annotation.processing.*; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +@Target({ElementType.TYPE}) +public @interface PythonClass {} \ No newline at end of file diff --git a/common/py/src/main/java/zingg/common/py/annotations/PythonMethod.java b/common/py/src/main/java/zingg/common/py/annotations/PythonMethod.java new file mode 100644 index 000000000..f59a9c038 --- /dev/null +++ b/common/py/src/main/java/zingg/common/py/annotations/PythonMethod.java @@ -0,0 +1,9 @@ +package zingg.common.py.annotations; + +import javax.annotation.processing.*; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +@Target({ElementType.METHOD}) +public @interface PythonMethod {} \ No newline at end of file diff --git a/common/py/src/main/java/zingg/common/py/processors/PythonClassProcessor.java b/common/py/src/main/java/zingg/common/py/processors/PythonClassProcessor.java new file mode 100644 index 000000000..1090628a2 --- /dev/null +++ b/common/py/src/main/java/zingg/common/py/processors/PythonClassProcessor.java @@ -0,0 +1,91 @@ +package zingg.common.py.processors; + +import java.util.List; +import javax.annotation.processing.*; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeKind; +import java.util.Set; +import javax.lang.model.element.*; +import javax.lang.model.util.ElementFilter; + +import zingg.common.py.annotations.*; + +@SupportedAnnotationTypes("zingg.common.py.annotations.PythonClass") +public class PythonClassProcessor extends AbstractProcessor { + + private boolean importsAndDeclarationsGenerated = false; + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + + // Imports and global declarations + if (!importsAndDeclarationsGenerated) { + generateImportsAndDeclarations(); + importsAndDeclarationsGenerated = true; + } + + + // process Services annotation + for (Element element : roundEnv.getElementsAnnotatedWith(PythonClass.class)) { + if (element.getKind() == ElementKind.CLASS) { + TypeElement classElement = (TypeElement) element; + PackageElement packageElement = + (PackageElement) classElement.getEnclosingElement(); + System.out.println("class " + element.getSimpleName() + ":"); + + // __init__ method + System.out.println(" def __init__(self" + + generateConstructorParameters(classElement) + "):"); + if (element.getSimpleName().contentEquals("EPipe")) { + generateClassInitializationCode(classElement); + } + for (VariableElement field : ElementFilter.fieldsIn(classElement.getEnclosedElements())) { + if (!field.getSimpleName().contentEquals("serialVersionUID")) { + generateFieldInitializationCode(field); + } + } + } + System.out.println(); + // rest of generated class contents + } + + return false; + + } + + private void generateImportsAndDeclarations() { + System.out.println("import logging"); + System.out.println("from zingg.client import *"); + System.out.println("LOG = logging.getLogger(\"zingg.pipes\")"); + System.out.println(); + System.out.println("JPipe = getJVM().zingg.spark.client.pipe.SparkPipe"); + System.out.println("FilePipe = getJVM().zingg.common.client.pipe.FilePipe"); + System.out.println("JStructType = getJVM().org.apache.spark.sql.types.StructType"); + System.out.println(); + } + + private void generateClassInitializationCode(TypeElement classElement) { + System.out.println(" self.EPipe = getJVM().zingg.spark.client.pipe.SparkPipe()"); + } + + // private void generateFieldInitializationCode(VariableElement field, ExecutableElement methodElement, TypeElement classElement) { + private void generateFieldInitializationCode(VariableElement field) { + System.out.println(" self.EPipe." + field.getSimpleName() + " = " + field.getSimpleName()); + // String fieldName = field.getSimpleName().toString(); + // String methodName = methodElement.getSimpleName().toString(); + // System.out.println(" self." + fieldName + " = " + "getJVM()." + + // classElement.getQualifiedName().toString() + "." + methodName + "(" + fieldName + ")"); + } + + private String generateConstructorParameters(TypeElement classElement) { + StringBuilder parameters = new StringBuilder(); + for (VariableElement field : ElementFilter.fieldsIn(classElement.getEnclosedElements())) { + if (!field.getSimpleName().contentEquals("serialVersionUID")) { + parameters.append(", "); + parameters.append(field.getSimpleName()); + } + } + return parameters.toString(); + } + +} diff --git a/common/py/src/main/java/zingg/common/py/processors/PythonMethodProcessor.java b/common/py/src/main/java/zingg/common/py/processors/PythonMethodProcessor.java new file mode 100644 index 000000000..fe0b02747 --- /dev/null +++ b/common/py/src/main/java/zingg/common/py/processors/PythonMethodProcessor.java @@ -0,0 +1,76 @@ +package zingg.common.py.processors; + +import java.util.List; +import javax.annotation.processing.*; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeKind; +import java.util.Set; +import javax.lang.model.element.*; +import javax.lang.model.util.ElementFilter; + +import zingg.common.py.annotations.*; + +@SupportedAnnotationTypes("zingg.common.py.annotations.PythonMethod") +public class PythonMethodProcessor extends AbstractProcessor { + + private boolean importsAndDeclarationsGenerated = false; + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + + // process Services annotation + for (Element element : roundEnv.getElementsAnnotatedWith(PythonMethod.class)) { + + if (element.getKind() == ElementKind.METHOD) { + ExecutableElement methodElement = (ExecutableElement) element; + System.out.println(" def " + methodElement.getSimpleName() + "(self" + + generateMethodSignature(methodElement) + "):\n " + generateMethodReturn(methodElement)); + generateFieldAssignment(methodElement); + } + System.out.println(); + + // rest of generated class contents + } + return false; + } + + private String generateMethodSignature(ExecutableElement methodElement) { + StringBuilder signature = new StringBuilder(); + signature.append(generateMethodParameters(methodElement)); + return signature.toString(); + } + + private String generateMethodParameters(ExecutableElement methodElement) { + StringBuilder parameters = new StringBuilder(); + for (VariableElement parameter : methodElement.getParameters()) { + parameters.append(", "); + parameters.append(parameter.getSimpleName()); + } + return parameters.toString(); + } + + private String generateMethodReturn(ExecutableElement methodElement) { + TypeMirror returnType = methodElement.getReturnType(); + if (returnType.getKind() == TypeKind.VOID) { + return ""; + } else { + String returnTypeString = resolveType(returnType); + String variableName = methodElement.getSimpleName().toString(); + return "return " + variableName; + } + } + + private String resolveType(TypeMirror typeMirror) { + return typeMirror.toString(); + } + + private void generateFieldAssignment(ExecutableElement methodElement) { + List parameters = methodElement.getParameters(); + if (!parameters.isEmpty()) { + VariableElement parameter = parameters.get(0); + String variableName = parameter.getSimpleName().toString(); + System.out.println(" self." + variableName + " = " + variableName); + } +} + +}