/*
* 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.artifact;
import griffon.metadata.ArtifactProviderFor;
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.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
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 ArtifactProviderProcessor extends AbstractSpiProcessor {
public static final String NAME = ArtifactProviderProcessor.class.getName()
+ " (" + ArtifactProviderProcessor.class.getPackage().getImplementationVersion() + ")";
private static final int MAX_SUPPORTED_VERSION = 8;
private Persistence persistence;
private ArtifactCollector data;
@Override
protected Class<? extends Annotation> getAnnotationClass() {
return ArtifactProviderFor.class;
}
@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 void initialize() {
super.initialize();
persistence = new ArtifactPersistence(NAME, options.dir(), processingEnv.getFiler(), logger);
data = new ArtifactCollector(persistence.getInitializer(), logger);
// Initialize if possible
for (String artifactName : persistence.tryFind()) {
data.getArtifact(artifactName);
}
data.cache();
}
@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) {
processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage());
}
}
persistence.writeLog();
}
}
}
@Override
protected void removeStaleData(RoundEnvironment roundEnv) {
for (Element e : roundEnv.getRootElements()) {
if (e instanceof TypeElement) {
TypeElement currentClass = (TypeElement) e;
data.removeProvider(createProperQualifiedName(currentClass));
}
}
}
@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 artifact : findArtifacts(currentClass)) {
CheckResult implementationResult = isImplementation(currentClass, artifact);
if (implementationResult.isError()) {
reportError(currentClass, implementationResult);
} else {
register(createProperQualifiedName(artifact), currentClass);
}
}
}
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");
}
return CheckResult.OK;
}
private List<TypeElement> findArtifacts(TypeElement classElement) {
List<TypeElement> artifacts = new ArrayList<>();
for (AnnotationMirror annotation : findAnnotationMirrors(classElement, getAnnotationClass().getName())) {
artifacts.add(toElement(findSingleValueMember(annotation, "value")));
}
return artifacts;
}
private void register(String artifactName, TypeElement provider) {
data.getArtifact(artifactName).addProvider(createProperQualifiedName(provider));
}
}