/* * Copyright 2008-2017 the original author or authors. * * 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.codehaus.griffon.compile.core.processor.editor; import griffon.metadata.PropertyEditorFor; import org.kordamp.jipsy.processor.AbstractSpiProcessor; import org.kordamp.jipsy.processor.CheckResult; import org.kordamp.jipsy.processor.LogLocation; import org.kordamp.jipsy.processor.Options; import org.kordamp.jipsy.processor.Persistence; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedOptions; import javax.lang.model.SourceVersion; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; 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.Diagnostic; import java.beans.PropertyEditor; import java.io.IOException; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; /** * @author Andres Almiray */ @SupportedAnnotationTypes("*") @SupportedOptions({Options.SPI_DIR_OPTION, Options.SPI_LOG_OPTION, Options.SPI_VERBOSE_OPTION, Options.SPI_DISABLED_OPTION}) public class PropertyEditorProcessor extends AbstractSpiProcessor { public static final String NAME = PropertyEditorProcessor.class.getName() + " (" + PropertyEditorProcessor.class.getPackage().getImplementationVersion() + ")"; private static final int MAX_SUPPORTED_VERSION = 8; private Persistence persistence; private PropertyEditorCollector data; private TypeElement propertyEditorType; @Override public SourceVersion getSupportedSourceVersion() { SourceVersion[] svs = SourceVersion.values(); for (int i = svs.length - 1; i >= 0; i--) { String name = svs[i].name(); Matcher m = RELEASE_PATTERN.matcher(name); if (m.matches()) { int release = Integer.parseInt(m.group(1)); if (release <= MAX_SUPPORTED_VERSION) return svs[i]; } } return SourceVersion.RELEASE_6; } @Override protected Class<? extends Annotation> getAnnotationClass() { return PropertyEditorFor.class; } @Override protected void initialize() { super.initialize(); persistence = new PropertyEditorPersistence(NAME, options.dir(), processingEnv.getFiler(), logger); propertyEditorType = processingEnv.getElementUtils().getTypeElement(PropertyEditor.class.getName()); data = new PropertyEditorCollector(persistence.getInitializer(), logger); data.load(); } @Override protected void handleElement(Element e) { if (!(e instanceof TypeElement)) { return; } TypeElement currentClass = (TypeElement) e; CheckResult checkResult = checkCurrentClass(currentClass); if (checkResult.isError()) { reportError(currentClass, checkResult); return; } for (TypeElement type : findTypes(currentClass)) { CheckResult implementationResult = isImplementation(currentClass, propertyEditorType); if (implementationResult.isError()) { reportError(currentClass, implementationResult); } else { register(createProperQualifiedName(type), currentClass); } } } @Override protected void removeStaleData(RoundEnvironment roundEnv) { for (Element e : roundEnv.getRootElements()) { if (e instanceof TypeElement) { TypeElement currentClass = (TypeElement) e; data.removePropertyEditor(createProperQualifiedName(currentClass)); } } } @Override protected void writeData() { if (data.isModified()) { String content = data.toList(); if (content.length() > 0) { logger.note(LogLocation.LOG_FILE, "Writing output"); try { persistence.write(PropertyEditor.class.getName(), content); } catch (IOException ioe) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ioe.getMessage()); } persistence.writeLog(); } else { logger.note(LogLocation.LOG_FILE, "Writing output"); try { persistence.delete(); } catch (IOException e) { logger.warning(LogLocation.LOG_FILE, "An error occurred while deleting data file"); } } } } private CheckResult checkCurrentClass(TypeElement currentClass) { if (currentClass.getKind() != ElementKind.CLASS) { return CheckResult.valueOf("is not a class"); } if (!currentClass.getModifiers().contains(Modifier.PUBLIC)) { return CheckResult.valueOf("is not a public class"); } if (isAbstractClass(currentClass)) { return CheckResult.valueOf("is an abstract class"); } if (!hasPublicNoArgsConstructor(currentClass)) { return CheckResult.valueOf("has no public no-args constructor"); } return CheckResult.OK; } private List<TypeElement> findTypes(TypeElement classElement) { List<TypeElement> types = new ArrayList<>(); for (AnnotationMirror annotation : findAnnotationMirrors(classElement, getAnnotationClass().getName())) { for (AnnotationValue value : findCollectionValueMember(annotation, "value")) { types.add(toElement(value)); } } return types; } private void register(String type, TypeElement editorClass) { data.getPropertyEditor(type, createProperQualifiedName(editorClass)); } }