/* * 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.ast.editor; import griffon.metadata.PropertyEditorFor; import org.codehaus.griffon.compile.core.processor.editor.PropertyEditorCollector; import org.codehaus.groovy.ast.AnnotationNode; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.ModuleNode; import org.codehaus.groovy.ast.expr.ClassExpression; import org.codehaus.groovy.ast.expr.Expression; import org.codehaus.groovy.control.CompilePhase; import org.codehaus.groovy.transform.ASTTransformation; import org.codehaus.groovy.transform.GroovyASTTransformation; import org.kordamp.gipsy.transform.GipsyASTTransformation; import org.kordamp.jipsy.ServiceProviderFor; import org.kordamp.jipsy.processor.CheckResult; import org.kordamp.jipsy.processor.LogLocation; import org.kordamp.jipsy.processor.Persistence; import java.beans.PropertyEditor; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import static java.lang.reflect.Modifier.isAbstract; import static java.lang.reflect.Modifier.isPublic; /** * @author Andres Almiray */ @ServiceProviderFor(ASTTransformation.class) @GroovyASTTransformation(phase = CompilePhase.CLASS_GENERATION) public class PropertyEditorASTTransformation extends GipsyASTTransformation { public static final String NAME = PropertyEditorASTTransformation.class.getName() + " (" + PropertyEditorASTTransformation.class.getPackage().getImplementationVersion() + ")"; private static final ClassNode PROPERTY_EDITOR_FOR_TYPE = makeClassSafe(PropertyEditorFor.class); private static final ClassNode PROPERTY_EDITOR_TYPE = makeClassSafe(PropertyEditor.class); private Persistence persistence; private PropertyEditorCollector data; @Override protected ClassNode getAnnotationClassNode() { return PROPERTY_EDITOR_FOR_TYPE; } @Override protected void initialize(ModuleNode moduleNode) { super.initialize(moduleNode); File outputDir = moduleNode.getContext().getConfiguration().getTargetDirectory(); persistence = new PropertyEditorPersistence(NAME, options.dir(), outputDir, logger); data = new PropertyEditorCollector(persistence.getInitializer(), logger); data.load(); } @Override protected void removeStaleData(ClassNode classNode, ModuleNode moduleNode) { data.removePropertyEditor(classNode.getName()); } protected void handleAnnotations(ClassNode classNode, List<AnnotationNode> annotations, ModuleNode moduleNode) { CheckResult checkResult = checkCurrentClass(classNode); if (checkResult.isError()) { addError(checkResult.getMessage(), classNode, moduleNode.getContext()); return; } for (ClassNode type : findTypes(annotations)) { CheckResult implementationResult = isImplementation(classNode, PROPERTY_EDITOR_TYPE); if (implementationResult.isError()) { addError(implementationResult.getMessage(), classNode, moduleNode.getContext()); } else { register(type.getName(), classNode); } } } @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) { // TODO print out error } 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(ClassNode currentClass) { if (currentClass.isInterface()) { return CheckResult.valueOf("is not a class"); } if (!isPublic(currentClass.getModifiers())) { return CheckResult.valueOf("is not a public class"); } if (isAbstract(currentClass.getModifiers())) { return CheckResult.valueOf("is an abstract class"); } if (!hasNoArgsConstructor(currentClass)) { return CheckResult.valueOf("has no public no-args constructor"); } return CheckResult.OK; } private List<ClassNode> findTypes(List<AnnotationNode> annotations) { List<ClassNode> types = new ArrayList<>(); for (AnnotationNode annotation : annotations) { for (Expression expr : findCollectionValueMember(annotation, "value")) { if (expr instanceof ClassExpression) { types.add(((ClassExpression) expr).getType()); } } } return types; } private void register(String type, ClassNode editor) { data.getPropertyEditor(type, editor.getName()); } }