/* * 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.artifact; import griffon.metadata.ArtifactProviderFor; import org.codehaus.griffon.compile.core.processor.artifact.Artifact; import org.codehaus.griffon.compile.core.processor.artifact.ArtifactCollector; 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.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; /** * @author Andres Almiray */ @ServiceProviderFor(ASTTransformation.class) @GroovyASTTransformation(phase = CompilePhase.CLASS_GENERATION) public class ArtifactProviderASTTransformation extends GipsyASTTransformation { public static final String NAME = ArtifactProviderASTTransformation.class.getName() + " (" + ArtifactProviderASTTransformation.class.getPackage().getImplementationVersion() + ")"; private static final ClassNode SERVICE_PROVIDER_FOR_TYPE = makeClassSafe(ArtifactProviderFor.class); private Persistence persistence; private ArtifactCollector data; @Override protected ClassNode getAnnotationClassNode() { return SERVICE_PROVIDER_FOR_TYPE; } @Override protected void initialize(ModuleNode moduleNode) { super.initialize(moduleNode); File outputDir = moduleNode.getContext().getConfiguration().getTargetDirectory(); persistence = new ArtifactPersistence(NAME, options.dir(), outputDir, logger); data = new ArtifactCollector(persistence.getInitializer(), logger); // Initialize if possible for (String artifactName : persistence.tryFind()) { data.getArtifact(artifactName); } //data.cache(); } @Override protected void removeStaleData(ClassNode classNode, ModuleNode moduleNode) { data.removeProvider(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 artifact : findArtifacts(annotations)) { CheckResult implementationResult = isImplementation(classNode, artifact); if (implementationResult.isError()) { addError(implementationResult.getMessage(), classNode, moduleNode.getContext()); } else { register(artifact.getName(), classNode); } } } @Override protected void writeData() { // if (data.isModified()) { if (data.artifacts().isEmpty()) { 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"); } } else { logger.note(LogLocation.LOG_FILE, "Writing output"); for (Artifact artifact : data.artifacts()) { try { persistence.write(artifact.getName(), artifact.toProviderNamesList()); } catch (IOException e) { // TODO print out error } } persistence.writeLog(); } // } } 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 (isStatic(currentClass.getModifiers())) { return CheckResult.valueOf("is a static class"); } /* if (!hasNoArgsConstructor(currentClass)) { return CheckResult.valueOf("has no public no-args constructor"); } */ return CheckResult.OK; } private List<ClassNode> findArtifacts(List<AnnotationNode> annotations) { List<ClassNode> artifacts = new ArrayList<>(); for (AnnotationNode annotation : annotations) { for (Expression expr : findCollectionValueMember(annotation, "value")) { if (expr instanceof ClassExpression) { artifacts.add(((ClassExpression) expr).getType()); } } } return artifacts; } private void register(String artifactName, ClassNode provider) { data.getArtifact(artifactName).addProvider(provider.getName()); } }