All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.swirlds.config.processor.ConfigDataAnnotationProcessor Maven / Gradle / Ivy

Go to download

Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.

There is a newer version: 0.56.5
Show newest version
/*
 * Copyright (C) 2023-2024 Hedera Hashgraph, LLC
 *
 * 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 com.swirlds.config.processor;

import static com.swirlds.config.processor.ConfigProcessorConstants.CONSTANTS_CLASS_SUFFIX;

import com.google.auto.service.AutoService;
import com.swirlds.config.processor.antlr.AntlrConfigRecordParser;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
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.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;

/**
 * An annotation processor that creates documentation and constants for config data records.
 */
@SupportedAnnotationTypes(ConfigProcessorConstants.CONFIG_DATA_ANNOTATION)
@SupportedSourceVersion(SourceVersion.RELEASE_21)
@AutoService(Processor.class)
public final class ConfigDataAnnotationProcessor extends AbstractProcessor {

    @Override
    public boolean process(
            final @NonNull Set annotations, final @NonNull RoundEnvironment roundEnv) {
        Objects.requireNonNull(roundEnv, "annotations must not be null");
        Objects.requireNonNull(roundEnv, "roundEnv must not be null");

        if (annotations.isEmpty()) {
            return false;
        }
        final String executionPath = System.getProperty("user.dir");
        final Path configDocumentationFile = Paths.get(executionPath, "build/docs/config.md");
        try {
            Files.deleteIfExists(configDocumentationFile);
        } catch (final IOException e) {
            throw new RuntimeException("Error while deleting " + configDocumentationFile, e);
        }
        configDocumentationFile.toFile().getParentFile().mkdirs();

        log("Config Data Annotation Processor started...");
        try {
            annotations.stream()
                    .map(annotation -> (TypeElement) annotation)
                    .flatMap(annotation -> roundEnv.getElementsAnnotatedWith(annotation).stream())
                    .filter(element -> element.getKind() == ElementKind.RECORD)
                    .filter(element -> element instanceof TypeElement)
                    .map(TypeElement.class::cast)
                    .forEach(typeElement -> handleTypeElement(typeElement, configDocumentationFile));
            return true;
        } catch (final Exception e) {
            log(Kind.ERROR, "Error while processing annotations: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    private void handleTypeElement(
            @NonNull final TypeElement typeElement, @NonNull final Path configDocumentationFile) {
        final String simpleClassName = typeElement.getSimpleName().toString();
        final String fileName = simpleClassName + ConfigProcessorConstants.JAVA_FILE_EXTENSION;

        final String packageName = processingEnv
                .getElementUtils()
                .getPackageOf(typeElement)
                .getQualifiedName()
                .toString();
        log("handling: " + fileName + " in " + packageName);
        try {
            final FileObject recordSource = getSource(fileName, packageName);
            final List recordDefinitions = AntlrConfigRecordParser.parse(
                    recordSource.getCharContent(true).toString());

            if (!recordDefinitions.isEmpty()) {
                final JavaFileObject constantsSourceFile =
                        getConstantSourceFile(packageName, simpleClassName, typeElement);
                log("generating config constants file: " + constantsSourceFile.getName());
                ConstantClassFactory.doWork(recordDefinitions.getFirst(), constantsSourceFile);
                log("generating config doc file: " + configDocumentationFile.getFileName());
                DocumentationFactory.doWork(recordDefinitions.getFirst(), configDocumentationFile);
            }
        } catch (final Exception e) {
            throw new RuntimeException("Error handling " + typeElement, e);
        }
    }

    @NonNull
    private JavaFileObject getConstantSourceFile(
            @NonNull final String packageName,
            @NonNull final String simpleClassName,
            @NonNull final TypeElement originatingElement)
            throws IOException {
        Objects.requireNonNull(packageName, "packageName must not be null");
        Objects.requireNonNull(simpleClassName, "simpleClassName must not be null");
        Objects.requireNonNull(originatingElement, "originatingElement must not be null");

        final String constantsClassName = packageName + "." + simpleClassName + CONSTANTS_CLASS_SUFFIX;
        return processingEnv.getFiler().createSourceFile(constantsClassName, originatingElement);
    }

    @NonNull
    private FileObject getSource(@NonNull final String fileName, @NonNull final String packageName) throws IOException {
        Objects.requireNonNull(fileName, "fileName must not be null");
        Objects.requireNonNull(packageName, "packageName must not be null");

        return processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, packageName, fileName);
    }

    private void log(@NonNull final String message) {
        log(Kind.OTHER, message);
    }

    private void log(@NonNull final Kind kind, @NonNull final String message) {
        Objects.requireNonNull(message, "message must not be null");

        processingEnv
                .getMessager()
                .printMessage(kind, ConfigDataAnnotationProcessor.class.getSimpleName() + ": " + message);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy