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

hudson.plugins.checkstyle.util.model.AnnotationContainer Maven / Gradle / Ivy

Go to download

This plug-in generates the trend report for Checkstyle, an open source static code analysis program.

There is a newer version: 3.12
Show newest version
package hudson.plugins.checkstyle.util.model; // NOPMD

import hudson.plugins.checkstyle.util.Messages;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import edu.umd.cs.findbugs.annotations.SuppressWarnings;

/**
 * A container for annotations.
 *
 * @author Ulli Hafner
 */
public abstract class AnnotationContainer implements AnnotationProvider, Serializable, Comparable {
    /** Unique identifier of this class. */
    private static final long serialVersionUID = 855696821788264261L;
    /** The hierarchy of a container. */
    public enum Hierarchy {
        /** Project level. */
        PROJECT,
        /** Module level. */
        MODULE,
        /** Package level. */
        PACKAGE,
        /** File level. */
        FILE}

    /** The annotations mapped by their key. */
    @SuppressWarnings("Se")
    private final Map annotations = new HashMap();
    /** The annotations mapped by priority. */
    private transient Map> annotationsByPriority;
    /** The annotations mapped by category. */
    private transient Map> annotationsByCategory;
    /** The annotations mapped by type. */
    private transient Map> annotationsByType;
    /** The files that contain annotations mapped by file name. */
    private transient Map filesByName;
    /** The packages that contain annotations mapped by package name. */
    private transient Map packagesByName;
    /** The modules that contain annotations mapped by module name. */
    private transient Map modulesByName;
    /** The files that contain annotations mapped by hash code of file name. */
    private transient Map filesByHashCode;
    /** The packages that contain annotations mapped by hash code of package name. */
    private transient Map packagesByHashCode;
    /** The modules that contain annotations mapped by hash code of module name. */
    private transient Map modulesByHashCode;
    /** The modules that contain annotations mapped by hash code of category name. */
    private transient Map> categoriesByHashCode;
    /** The modules that contain annotations mapped by hash code of type name. */
    private transient Map> typesByHashCode;

    /** Determines whether to build up a set of {@link WorkspaceFile}s. */
    @java.lang.SuppressWarnings("unused")
    private boolean handleFiles; // backward compatibility NOPMD

    /** Name of this container. */
    private String name;
    /** Hierarchy level of this container. */
    private Hierarchy hierarchy;

    /**
     * Creates a new instance of AnnotationContainer.
     *
     * @param hierarchy the hierarchy of this container
     */
    public AnnotationContainer(final Hierarchy hierarchy) {
        this(StringUtils.EMPTY, hierarchy);
    }

    /**
     * Returns this container.
     *
     * @return this container
     */
    public AnnotationContainer getContainer() {
        return this;
    }

    /**
     * Gets the maximum number of annotations within the specified containers.
     *
     * @param containers
     *            the containers to scan for the upper bound
     * @return the maximum number of annotations
     */
    public int getUpperBound(final Collection containers) {
        int maximum = 0;
        for (AnnotationContainer container : containers) {
            maximum = Math.max(maximum, container.getNumberOfAnnotations());
        }
        return maximum;
    }

    /**
     * Creates a new instance of AnnotationContainer.
     *
     * @param name the name of this container
     * @param hierarchy the hierarchy of this container
     */
    protected AnnotationContainer(final String name, final Hierarchy hierarchy) {
        initialize();
        this.name = name;
        this.hierarchy = hierarchy;
    }

    /**
     * Sets the hierarchy to the specified value.
     *
     * @param hierarchy the value to set
     */
    protected void setHierarchy(final Hierarchy hierarchy) {
        this.hierarchy = hierarchy;
    }

    /**
     * Returns the name of this container.
     *
     * @return the name of this container
     */
    public final String getName() {
        return name;
    }

    /**
     * Sets the name of this container.
     *
     * @param name the name of this container
     */
    public final void setName(final String name) {
        this.name = name;
    }

    /**
     * Initializes the transient mappings.
     */
    private void initialize() {
        annotationsByPriority = new EnumMap>(Priority.class);
        for (Priority priority : Priority.values()) {
            annotationsByPriority.put(priority, new HashSet());
        }
        annotationsByCategory = new HashMap>();
        annotationsByType = new HashMap>();
        filesByName = new HashMap();
        packagesByName = new HashMap();
        modulesByName = new HashMap();
        filesByHashCode = new HashMap();
        packagesByHashCode = new HashMap();
        modulesByHashCode = new HashMap();
        categoriesByHashCode = new HashMap>();
        typesByHashCode = new HashMap>();
    }

    /**
     * Rebuilds the priorities mapping.
     *
     * @return the created object
     */
    @SuppressWarnings("Se")
    private Object readResolve() {
        rebuildMappings();
        return this;
    }

    /**
     * Rebuilds the priorities and files after deserialization.
     */
    protected void rebuildMappings() {
        initialize();
        for (FileAnnotation annotation : getAnnotations()) {
            updateMappings(annotation);
        }
    }

    /**
     * Updates the annotation drill-down mappings (priority, packages, files) with the specified annotation.
     *
     * @param annotation the new annotation
     */
    private void updateMappings(final FileAnnotation annotation) {
        annotationsByPriority.get(annotation.getPriority()).add(annotation);
        if (StringUtils.isNotBlank(annotation.getCategory())) {
            addCategory(annotation);
        }
        if (StringUtils.isNotBlank(annotation.getType())) {
            addType(annotation);
        }
        if (hierarchy == Hierarchy.PROJECT) {
            addModule(annotation);
        }
        if (hierarchy == Hierarchy.PROJECT || hierarchy == Hierarchy.MODULE) {
            addPackage(annotation);
        }
        if (hierarchy == Hierarchy.PROJECT || hierarchy == Hierarchy.MODULE || hierarchy == Hierarchy.PACKAGE) {
            addFile(annotation);
        }
    }

    /**
     * Adds a new category to this container that will contain the specified
     * annotation. If the category already exists, then the annotation is only added
     * to this category.
     *
     * @param annotation the new annotation
     */
    private void addCategory(final FileAnnotation annotation) {
        String category = annotation.getCategory();
        if (!annotationsByCategory.containsKey(category)) {
            HashSet container = new HashSet();
            annotationsByCategory.put(category, container);
            categoriesByHashCode.put(category.hashCode(), container);
        }
        annotationsByCategory.get(category).add(annotation);
    }

    /**
     * Adds a new type to this container that will contain the specified
     * annotation. If the type already exists, then the annotation is only added
     * to this type.
     *
     * @param annotation the new annotation
     */
    private void addType(final FileAnnotation annotation) {
        String type = annotation.getType();
        if (!annotationsByType.containsKey(type)) {
            HashSet container = new HashSet();
            annotationsByType.put(type, container);
            typesByHashCode.put(type.hashCode(), container);
        }
        annotationsByType.get(type).add(annotation);
    }

    /**
     * Adds a new module to this container that will contain the specified
     * annotation. If the module already exists, then the annotation is only added
     * to this module.
     *
     * @param annotation the new annotation
     */
    private void addModule(final FileAnnotation annotation) {
        String moduleName = annotation.getModuleName();
        if (!modulesByName.containsKey(moduleName)) {
            MavenModule module = new MavenModule(moduleName);
            modulesByName.put(moduleName, module);
            modulesByHashCode.put(moduleName.hashCode(), module);
        }
        modulesByName.get(moduleName).addAnnotation(annotation);
    }

    /**
     * Adds a new package to this container that will contain the specified
     * annotation. If the package already exists, then the annotation is only added
     * to this package.
     *
     * @param annotation the new annotation
     */
    private void addPackage(final FileAnnotation annotation) {
        String packageName = annotation.getPackageName();
        if (!packagesByName.containsKey(packageName)) {
            JavaPackage javaPackage = new JavaPackage(packageName);
            packagesByName.put(packageName, javaPackage);
            packagesByHashCode.put(packageName.hashCode(), javaPackage);
        }
        packagesByName.get(packageName).addAnnotation(annotation);
    }

    /**
     * Adds a new file to this container that will contain the specified
     * annotation. If the file already exists, then the annotation is only added
     * to this class.
     *
     * @param annotation the new annotation
     */
    private void addFile(final FileAnnotation annotation) {
        String fileName = annotation.getFileName();
        if (!filesByName.containsKey(fileName)) {
            WorkspaceFile file = new WorkspaceFile(fileName);
            filesByName.put(fileName, file);
            filesByHashCode.put(file.getName().hashCode(), file);
        }
        filesByName.get(fileName).addAnnotation(annotation);
    }

    /**
     * Adds the specified annotation to this container.
     *
     * @param annotation the annotation to add
     */
    public final void addAnnotation(final FileAnnotation annotation) {
        annotations.put(annotation.getKey(), annotation);
        updateMappings(annotation);
    }

    /**
     * Adds the specified annotations to this container.
     *
     * @param newAnnotations the annotations to add
     */
    public final void addAnnotations(final Collection newAnnotations) {
        for (FileAnnotation annotation : newAnnotations) {
            addAnnotation(annotation);
        }
    }

    /**
     * Adds the specified annotations to this container.
     *
     * @param newAnnotations the annotations to add
     */
    public final void addAnnotations(final FileAnnotation[] newAnnotations) {
        addAnnotations(Arrays.asList(newAnnotations));
    }

    /** {@inheritDoc} */
    public final Collection getAnnotations() {
        ArrayList all = new ArrayList(annotations.values());
        Collections.sort(all);
        return Collections.unmodifiableCollection(all);
    }

    /** {@inheritDoc} */
    public final Collection getAnnotations(final Priority priority) {
        return Collections.unmodifiableCollection(annotationsByPriority.get(priority));
    }

    /**
     * Returns the annotations with {@link Priority#HIGH}.
     *
     * @return the annotations with {@link Priority#HIGH}
     */
    public final Collection getHighAnnotations() {
        return getAnnotations(Priority.HIGH);
    }

    /**
     * Returns the annotations with {@link Priority#NORMAL}.
     *
     * @return the annotations with {@link Priority#NORMAL}
     */
    public final Collection getNormalAnnotations() {
        return getAnnotations(Priority.NORMAL);
    }

    /**
     * Returns the annotations with {@link Priority#LOW}.
     *
     * @return the annotations with {@link Priority#LOW}
     */
    public final Collection getLowAnnotations() {
        return getAnnotations(Priority.LOW);
    }

    /** {@inheritDoc} */
    public final Collection getAnnotations(final String priority) {
        return getAnnotations(getPriority(priority));
    }

    /**
     * Converts a String priority to an actual enumeration value.
     *
     * @param priority priority as a String
     *
     * @return enumeration value.
     */
    private Priority getPriority(final String priority) {
        return Priority.fromString(priority);
    }

    /** {@inheritDoc} */
    public int getNumberOfAnnotations() {
        return annotations.size();
    }

    /**
     * Gets the number of annotations with priority low.
     *
     * @return the number of annotations with priority low
     */
    public int getNumberOfLowAnnotations() {
        return getLowAnnotations().size();
    }

    /**
     * Gets the number of annotations with priority normal.
     *
     * @return the number of annotations with priority normal
     */
    public int getNumberOfNormalAnnotations() {
        return getNormalAnnotations().size();
    }

    /**
     * Gets the number of annotations with priority high.
     *
     * @return the number of annotations with priority high
     */
    public int getNumberOfHighAnnotations() {
        return getHighAnnotations().size();
    }

    /** {@inheritDoc} */
    public int getNumberOfAnnotations(final Priority priority) {
        return annotationsByPriority.get(priority).size();
    }

    /** {@inheritDoc} */
    public final int getNumberOfAnnotations(final String priority) {
        return getNumberOfAnnotations(getPriority(priority));
    }

    /** {@inheritDoc} */
    public final boolean hasAnnotations() {
        return !hasNoAnnotations();
    }

    /** {@inheritDoc} */
    public final boolean hasAnnotations(final Priority priority) {
        return !hasNoAnnotations(priority);
    }

    /** {@inheritDoc} */
    public final boolean hasAnnotations(final String priority) {
        return !hasNoAnnotations(priority);
    }

    /** {@inheritDoc} */
    public final boolean hasNoAnnotations() {
        return annotations.isEmpty();
    }

    /** {@inheritDoc} */
    public final boolean hasNoAnnotations(final Priority priority) {
        return annotationsByPriority.get(priority).isEmpty();
    }

    /** {@inheritDoc} */
    public final boolean hasNoAnnotations(final String priority) {
        return hasNoAnnotations(getPriority(priority));
    }

    /** {@inheritDoc} */
    public final FileAnnotation getAnnotation(final long key) {
        FileAnnotation annotation = annotations.get(key);
        if (annotation != null) {
            return annotation;
        }
        throw new NoSuchElementException("Annotation not found: key=" + key);
    }

    /** {@inheritDoc} */
    public final FileAnnotation getAnnotation(final String key) {
        return getAnnotation(Long.parseLong(key));
    }

    /**
     * Returns a tooltip showing the distribution of priorities for this container.
     *
     * @return a tooltip showing the distribution of priorities
     */
    public String getToolTip() {
        StringBuilder message = new StringBuilder();
        for (Priority priority : Priority.values()) {
            if (hasAnnotations(priority)) {
                message.append(priority.getLocalizedString());
                message.append(":");
                message.append(getNumberOfAnnotations(priority));
                message.append(" - ");
            }
        }
        return StringUtils.removeEnd(message.toString(), " - ");
    }


    /**
     * Returns the package category name for the scanned files. Currently, only
     * java and c# files are supported.
     *
     * @return the package category name for the scanned files
     */
    public final String getPackageCategoryName() {
        if (hasAnnotations()) {
            String fileName = getAnnotations().iterator().next().getFileName();
            if (fileName.endsWith(".cs")) {
                return Messages.NamespaceDetail_header();
            }
        }
        return Messages.PackageDetail_header();
    }

    /**
     * Gets the modules of this container that have annotations.
     *
     * @return the modules with annotations
     */
    public Collection getModules() {
        ArrayList modules = new ArrayList(modulesByName.values());
        Collections.sort(modules);
        return Collections.unmodifiableCollection(modules);
    }

    /**
     * Returns whether the maven module with the given name exists.
     *
     * @param moduleName the module to check for
     *
     * @return true if the maven module with the given name
     * exists, false otherwise
     */
    public boolean containsModule(final String moduleName) {
        return modulesByName.containsKey(moduleName);
    }

    /**
     * Gets the module with the given name.
     *
     * @param moduleName the name of the module
     *
     * @return the module with the given name
     */
    public MavenModule getModule(final String moduleName) {
        if (modulesByName.containsKey(moduleName)) {
            return modulesByName.get(moduleName);
        }
        throw new NoSuchElementException("Module not found: " + moduleName);
    }

    /**
     * Gets the module with the given hash code.
     *
     * @param hashCode the hash code of the module
     *
     * @return the module with the given name
     */
    public MavenModule getModule(final int hashCode) {
        if (modulesByHashCode.containsKey(hashCode)) {
            return modulesByHashCode.get(hashCode);
        }
        throw new NoSuchElementException("Module not found: " + hashCode);
    }

    /**
     * Gets the packages of this container that have annotations.
     *
     * @return the packages with annotations
     */
    public Collection getPackages() {
        ArrayList packages = new ArrayList(packagesByName.values());
        Collections.sort(packages);
        return Collections.unmodifiableCollection(packages);
    }

    /**
     * Returns whether the package with the given name exists.
     *
     * @param packageName the package to check for
     *
     * @return true if the package with the given name
     * exists, false otherwise
     */
    public boolean containsPackage(final String packageName) {
        return packagesByName.containsKey(packageName);
    }

    /**
     * Gets the package with the given name.
     *
     * @param packageName the name of the package
     *
     * @return the file with the given name
     */
    public JavaPackage getPackage(final String packageName) {
        if (packagesByName.containsKey(packageName)) {
            return packagesByName.get(packageName);
        }
        throw new NoSuchElementException("Package not found: " + packageName);
    }

    /**
     * Gets the package with the given hash code.
     *
     * @param hashCode the hash code of the package
     *
     * @return the package with the given name
     */
    public JavaPackage getPackage(final int hashCode) {
        if (packagesByHashCode.containsKey(hashCode)) {
            return packagesByHashCode.get(hashCode);
        }
        throw new NoSuchElementException("Package not found: " + hashCode);
    }

    /**
     * Gets the files of this container that have annotations.
     *
     * @return the files with annotations
     */
    public Collection getFiles() {
        ArrayList files = new ArrayList(filesByName.values());
        Collections.sort(files);
        return Collections.unmodifiableCollection(files);
    }

    /**
     * Returns whether the file with the given name exists.
     *
     * @param fileName the file to check for
     *
     * @return true if the file with the given name
     * exists, false otherwise
     */
    public boolean containsFile(final String fileName) {
        return filesByName.containsKey(fileName);
    }

    /**
     * Gets the file with the given name.
     *
     * @param fileName the short name of the file
     *
     * @return the file with the given name
     */
    public WorkspaceFile getFile(final String fileName) {
        if (filesByName.containsKey(fileName)) {
            return filesByName.get(fileName);
        }
        throw new NoSuchElementException("File not found: " + fileName);
    }

    /**
     * Gets the file with the given hash code.
     *
     * @param hashCode the hash code of the file
     *
     * @return the file with the given name
     */
    public WorkspaceFile getFile(final int hashCode) {
        if (filesByHashCode.containsKey(hashCode)) {
            return filesByHashCode.get(hashCode);
        }
        throw new NoSuchElementException("File not found: " + hashCode);
    }

    /**
     * Gets the categories of this container that have annotations.
     *
     * @return the categories with annotations
     */
    public Collection getCategories() {
        ArrayList categories = new ArrayList();
        for (String category : annotationsByCategory.keySet()) {
            categories.add(getCategory(category));
        }
        Collections.sort(categories);
        return categories;
    }

    /**
     * Returns whether the category with the given name exists.
     *
     * @param category the file to check for
     *
     * @return true if the category with the given name
     * exists, false otherwise
     */
    public boolean containsCategory(final String category) {
        return annotationsByCategory.containsKey(category);
    }

    /**
     * Gets the category with the given name.
     *
     * @param category the category name
     * @return the category with the given name
     */
    public DefaultAnnotationContainer getCategory(final String category) {
        if (annotationsByCategory.containsKey(category)) {
            return new DefaultAnnotationContainer(category, annotationsByCategory.get(category));
        }
        throw new NoSuchElementException("Category not found: " + category);
    }

    /**
     * Gets the category with the given hash code.
     *
     * @param hashCode the category hash code
     * @return the category with the given hash code
     */
    public DefaultAnnotationContainer getCategory(final int hashCode) {
        if (categoriesByHashCode.containsKey(hashCode)) {
            Set container = categoriesByHashCode.get(hashCode);
            FileAnnotation fileAnnotation = container.iterator().next();
            return new DefaultAnnotationContainer(fileAnnotation.getCategory(), container);
        }
        throw new NoSuchElementException("Category not found: " + hashCode);
    }

    /**
     * Gets the types of this container that have annotations.
     *
     * @return the types with annotations
     */
    public Collection getTypes() {
        ArrayList types = new ArrayList();
        for (String type : annotationsByType.keySet()) {
            types.add(getType(type));
        }
        Collections.sort(types);
        return types;
    }

    /**
     * Returns whether the type with the given name exists.
     *
     * @param type the type to check for
     *
     * @return true if the type with the given name
     * exists, false otherwise
     */
    public boolean containsType(final String type) {
        return annotationsByType.containsKey(type);
    }

    /**
     * Gets the type with the given name.
     *
     * @param type the type name
     * @return the type with the given name
     */
    public DefaultAnnotationContainer getType(final String type) {
        if (annotationsByType.containsKey(type)) {
            return new DefaultAnnotationContainer(type, annotationsByType.get(type));
        }
        throw new NoSuchElementException("Type not found: " + type);
    }

    /**
     * Gets the type with the given hash code.
     *
     * @param hashCode the type hash code
     * @return the type with the given hash code
     */
    public DefaultAnnotationContainer getType(final int hashCode) {
        if (typesByHashCode.containsKey(hashCode)) {
            Set container = typesByHashCode.get(hashCode);
            FileAnnotation fileAnnotation = container.iterator().next();
            return new DefaultAnnotationContainer(fileAnnotation.getType(), container);
        }
        throw new NoSuchElementException("Type not found: " + hashCode);
    }

    /**
     * Returns {@link Priority#HIGH}.
     *
     * @return {@link Priority#HIGH}
     */
    public Priority getHighPriority() {
        return Priority.HIGH;
    }

    /**
     * Returns {@link Priority#NORMAL}.
     *
     * @return {@link Priority#NORMAL}
     */
    public Priority getNormalPriority() {
        return Priority.NORMAL;
    }

    /**
     * Returns {@link Priority#LOW}.
     *
     * @return {@link Priority#LOW}
     */
    public Priority getLowPriority() {
        return Priority.LOW;
    }

    /** {@inheritDoc} */
    public int compareTo(final AnnotationContainer other) {
        return getName().compareTo(other.getName());
    }

    /** {@inheritDoc} */
    @Override
    public int hashCode() {
        int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    /** {@inheritDoc} */
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        AnnotationContainer other = (AnnotationContainer)obj;
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        }
        else if (!name.equals(other.name)) {
            return false;
        }
        return true;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy