/* * Copyright 2017 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kie.workbench.common.stunner.svg.gen.apt; import java.util.List; import java.util.Set; import javax.annotation.processing.Messager; 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.ExecutableElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; import javax.tools.Diagnostic; import org.kie.workbench.common.stunner.svg.annotation.SVGSource; import org.kie.workbench.common.stunner.svg.gen.SVGGenerator; import org.kie.workbench.common.stunner.svg.gen.SVGGeneratorRequest; import org.kie.workbench.common.stunner.svg.gen.impl.SVGGeneratorFactory; import org.uberfire.annotations.processors.AbstractErrorAbsorbingProcessor; /** * Note that current implementation only considers a single SVGViewFactory for each module. */ @SupportedAnnotationTypes({SVGShapeProcessor.ANNOTATION_SVGSHAPE_VIEW_FACTORY}) @SupportedSourceVersion(SourceVersion.RELEASE_8) public class SVGShapeProcessor extends AbstractErrorAbsorbingProcessor { public final static String ANNOTATION_SVGSHAPE_VIEW_FACTORY = "org.kie.workbench.common.stunner.svg.annotation.SVGViewFactory"; private final static String GENERATED_TYPE_SUFFIX = "Impl"; private final SVGShapeProcessorContext context = new SVGShapeProcessorContext(); private SVGGenerator generator; @Override protected boolean processWithExceptions(Set<? extends TypeElement> set, RoundEnvironment roundEnv) throws Exception { if (roundEnv.processingOver()) { return processLastRound(set, roundEnv); } //If prior processing threw an error exit if (roundEnv.errorRaised()) { return false; } //Initialize the generator generator = SVGGeneratorFactory.newGenerator(); // Process SVG Shape View Factories for the annotated types. final Elements elementUtils = processingEnv.getElementUtils(); for (Element e : roundEnv.getElementsAnnotatedWith(elementUtils.getTypeElement(ANNOTATION_SVGSHAPE_VIEW_FACTORY))) { processSvgShapeViewFactory(set, e, roundEnv); } return true; } private boolean processSvgShapeViewFactory(final Set<? extends TypeElement> set, final Element e, final RoundEnvironment roundEnv) throws Exception { final boolean isIface = e.getKind() == ElementKind.INTERFACE; if (isIface) { final TypeElement classElement = (TypeElement) e; final PackageElement packageElement = (PackageElement) classElement.getEnclosingElement(); final String name = classElement.getSimpleName().toString(); // Obtain type element information and create a new generation request into the processor's context. String packageName = packageElement.getQualifiedName().toString(); String fqcn = packageName + "." + name; String absPkgPath = packageName.replaceAll("\\.", "/"); note("Discovered @SVGViewFactory for type [" + fqcn + "]"); final SVGGeneratorRequest request = new SVGGeneratorRequest(name + GENERATED_TYPE_SUFFIX, packageName, fqcn); context.setGeneratorRequest(request); // Find and process method annotation as @SVGSource. List<ExecutableElement> methodElements = ElementFilter.methodsIn(classElement.getEnclosedElements()); methodElements.forEach(methodElement -> { final List<? extends VariableElement> parameters = methodElement.getParameters(); if (null == parameters || parameters.size() != 3) { throw new IllegalArgumentException("Missing any of the arguments for view factory method [" + methodElement.getSimpleName().toString() + "]"); } SVGSource svgSourceAnnotation = methodElement.getAnnotation(SVGSource.class); if (null != svgSourceAnnotation) { String fileName = svgSourceAnnotation.value(); String absPath = absPkgPath + "/" + fileName; final String fieldName = methodElement.getSimpleName().toString(); note("Discovered @SVGSource to be processed at path [" + absPath + "]"); context.getGeneratorRequest().getViewSources().put(fieldName, absPath); } }); } return true; } private boolean processLastRound(final Set<? extends TypeElement> set, final RoundEnvironment roundEnv) throws Exception { final Messager messager = processingEnv.getMessager(); try { final SVGGeneratorRequest request = context.getGeneratorRequest(); final String classFQName = request.getPkg() + "." + request.getName(); messager.printMessage(Diagnostic.Kind.NOTE, "Starting generation for SVGShapeViewFactory named [" + classFQName + "]"); final StringBuffer result = generator.generate(request); writeCode(request.getPkg(), request.getName(), result); } catch (org.kie.workbench.common.stunner.svg.gen.exception.GeneratorException ge) { final String msg = ge.getMessage(); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg); } return true; } private void note(String message) { log(Diagnostic.Kind.NOTE, message); } private void warn(String message) { log(Diagnostic.Kind.WARNING, message); } private void error(String message) { log(Diagnostic.Kind.ERROR, message); } private void log(Diagnostic.Kind kind, String message) { final Messager messager = processingEnv.getMessager(); messager.printMessage(kind, message); } }