com.cognifide.aemrules.extensions.RulesLoader.java Source code

Java tutorial

Introduction

Here is the source code for com.cognifide.aemrules.extensions.RulesLoader.java

Source

/*-
 * #%L
 * AEM Rules for SonarQube
 * %%
 * Copyright (C) 2015 Cognifide Limited
 * %%
 * 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.
 * #L%
 */
package com.cognifide.aemrules.extensions;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Resources;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.AnnotationUtils;
import org.sonar.api.utils.FieldUtils2;
import org.sonar.check.Rule;
import org.sonar.plugins.java.api.JavaCheck;

import javax.annotation.CheckForNull;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.List;

public class RulesLoader {

    private static final Logger LOG = LoggerFactory.getLogger(RulesLoader.class);

    private static final Function<Class<?>, RuleParamType> TYPE_FOR_CLASS = Functions
            .forMap(ImmutableMap.<Class<?>, RuleParamType>builder().put(Integer.class, RuleParamType.INTEGER)
                    .put(int.class, RuleParamType.INTEGER).put(Float.class, RuleParamType.FLOAT)
                    .put(float.class, RuleParamType.FLOAT).put(Boolean.class, RuleParamType.BOOLEAN)
                    .put(boolean.class, RuleParamType.BOOLEAN).build(), RuleParamType.STRING);

    public void load(RulesDefinition.NewExtendedRepository repo,
            List<Class<? extends JavaCheck>> annotatedClasses) {
        for (Class<? extends JavaCheck> annotatedClass : annotatedClasses) {
            loadRule(repo, annotatedClass);
        }
    }

    @CheckForNull
    RulesDefinition.NewRule loadRule(RulesDefinition.NewExtendedRepository repo, Class<? extends JavaCheck> clazz) {
        Rule ruleAnnotation = AnnotationUtils.getAnnotation(clazz, Rule.class);
        if (ruleAnnotation != null) {
            return loadRule(repo, clazz, ruleAnnotation);
        } else {
            LOG.warn("The class {} should be annotated with {}", clazz.getCanonicalName(), Rule.class);
            return null;
        }
    }

    private RulesDefinition.NewRule loadRule(RulesDefinition.NewExtendedRepository repo,
            Class<? extends JavaCheck> clazz, Rule ruleAnnotation) {
        String ruleKey = StringUtils.defaultIfEmpty(ruleAnnotation.key(), clazz.getCanonicalName());
        String ruleName = StringUtils.defaultIfEmpty(ruleAnnotation.name(), null);
        String description = StringUtils.defaultIfEmpty(getDescriptionFromResources(ruleKey),
                "No description yet.");

        RulesDefinition.NewRule rule = repo.createRule(ruleKey);
        rule.setName(ruleName).setMarkdownDescription(description);
        rule.setSeverity(ruleAnnotation.priority().name());
        rule.setStatus(RuleStatus.valueOf(ruleAnnotation.status()));
        rule.setTags(ruleAnnotation.tags());

        List<Field> fields = FieldUtils2.getFields(clazz, true);
        for (Field field : fields) {
            loadParameters(rule, field);
        }

        return rule;
    }

    protected String getDescriptionFromResources(String ruleKey) {
        String result = null;
        try {
            String path = String.format("/rules/%s.md", ruleKey);
            URL url = Resources.getResource(RulesLoader.class, path);
            result = Resources.toString(url, Charsets.UTF_8);
        } catch (IOException | IllegalArgumentException e) {
            LOG.error("Cannot read resource file with rule description.", e);
        }
        return result;
    }

    private void loadParameters(RulesDefinition.NewRule rule, Field field) {
        org.sonar.check.RuleProperty propertyAnnotation = field.getAnnotation(org.sonar.check.RuleProperty.class);
        if (propertyAnnotation != null) {
            String fieldKey = StringUtils.defaultIfEmpty(propertyAnnotation.key(), field.getName());
            RulesDefinition.NewParam param = rule.createParam(fieldKey)
                    .setDescription(propertyAnnotation.description())
                    .setDefaultValue(propertyAnnotation.defaultValue());

            if (!StringUtils.isBlank(propertyAnnotation.type())) {
                try {
                    param.setType(RuleParamType.parse(propertyAnnotation.type().trim()));
                } catch (IllegalArgumentException e) {
                    throw new IllegalArgumentException("Invalid property type [" + propertyAnnotation.type() + "]",
                            e);
                }
            } else {
                param.setType(guessType(field.getType()));
            }
        }
    }

    @VisibleForTesting
    static RuleParamType guessType(Class<?> type) {
        return TYPE_FOR_CLASS.apply(type);
    }
}