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

com.google.security.fences.inheritance.InheritanceGraph Maven / Gradle / Ivy

Go to download

Augments Java's access control by checking that a Maven Project and all its dependencies conform to a policy that specifies which classes/packages can link to which others.

There is a newer version: 1.9-beta
Show newest version
package com.google.security.fences.inheritance;

import java.util.Map;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;

/**
 * A lazy-ish graph of sub/super-type relationships between Java classes.
 */
public final class InheritanceGraph {
  private final Map classNodes;
  private final Function fallback;

  InheritanceGraph(
      Map classNodes,
      Function fallback) {
    this.classNodes = Maps.newLinkedHashMap(classNodes);
    this.fallback = fallback;
  }

  /**
   * Returns the named node.
   *
   * @param name an internal class name like {@code com/example/MyClass}.
   */
  public Optional named(String name) {
    ClassNode node = classNodes.get(name);
    if (node == null && !classNodes.containsKey(name)) {
      classNodes.put(name, node = fallback.apply(name));
    }
    return Optional.fromNullable(node);
  }

  /** A builder that uses the pre-baked system class graph. */
  public static Builder builder() {
    return new Builder(SystemInheritanceGraph.LAZY_LOADER);
  }

  static Builder builder(Function fallback) {
    return new Builder(fallback);
  }

  /** A builder for {InheritanceGraph}s. */
  public static final class Builder {
    private final Map classNodes = Maps.newLinkedHashMap();
    private final Function lazyLoadSystemClass;
    private final Map outers = Maps.newLinkedHashMap();

    Builder(final Function lazyLoadSystemClass) {
      this.lazyLoadSystemClass = lazyLoadSystemClass;
    }

    /**
     * Defines a relationship between name and its super-interfaces.
     */
    public DeclarationBuilder declare(String name, int access) {
      return new DeclarationBuilder(name, access);
    }

    /** Single use builder.  State is cleared after call to build(). */
    public InheritanceGraph build() {
      return new InheritanceGraph(classNodes, lazyLoadSystemClass);
    }

    void classContains(String outer, String inner) {
      ClassNode innerNode = classNodes.get(inner);
      if (innerNode != null) {
        innerNode = new ClassNode(
            innerNode.name, innerNode.access, innerNode.superType,
            Optional.of(outer), innerNode.interfaces, innerNode.methods,
            innerNode.fields);
        classNodes.put(inner, innerNode);
      } else {
        outers.put(inner, outer);
      }
    }

    /**
     * Used to add additional details about a class.
     */
    public final class DeclarationBuilder {
      private final String name;
      private final int access;

      private Optional superClassName = Optional.of("java/lang/Object");
      private Optional outerClassName = Optional.absent();
      private ImmutableList.Builder interfaceNames =
          ImmutableList.builder();
      private ImmutableList.Builder methods =
          ImmutableList.builder();
      private ImmutableList.Builder fields =
          ImmutableList.builder();

      DeclarationBuilder(String name, int access) {
        this.name = name;
        this.access = access;
      }

      /** Sets the super-class name if any.  Null only for "java/lang/Object" */
      public DeclarationBuilder superClassName(
          Optional newSuperClassName) {
        this.superClassName = newSuperClassName;
        return this;
      }
      /** Sets the outer-class name if any. */
      public DeclarationBuilder outerClassName(
          Optional newOuterClassName) {
        this.outerClassName = newOuterClassName;
        return this;
      }
      /** Sets the interface list. */
      public DeclarationBuilder interfaceNames(
          Iterable newInterfaceNames) {
        this.interfaceNames.addAll(newInterfaceNames);
        return this;
      }
      /** Sets the list of declared methods. */
      public DeclarationBuilder methods(
          Iterable newMethods) {
        this.methods.addAll(newMethods);
        return this;
      }
      /** Sets the list of declared fields. */
      public DeclarationBuilder fields(
          Iterable newFields) {
        this.fields.addAll(newFields);
        return this;
      }

      /** Commit the built declaration into the parent builders map. */
      public Builder commit() {
        @SuppressWarnings("synthetic-access")
        Map classNodesMap = Builder.this.classNodes;
        @SuppressWarnings("synthetic-access")
        Map outersMap = Builder.this.outers;
        ClassNode node = classNodesMap.get(name);
        if (node == null) {
          Optional outer = outerClassName;
          if (!outer.isPresent()) {
            outer = Optional.fromNullable(outersMap.remove(name));
          }
          node = new ClassNode(
              name, access, superClassName, outer,
              interfaceNames.build(), methods.build(), fields.build());
          classNodesMap.put(name, node);
        }
        // Otherwise assume that subsequent declarations are from masked
        // class-files on the same class-path.
        return Builder.this;
      }
    }

  }

  /** All the names of class declared, or lazily fetched. */
  public Iterable allDeclaredNames() {
    return ImmutableList.copyOf(classNodes.keySet());
  }

  /** All the names of class declared, or lazily fetched. */
  public Iterable allDeclaredNodes() {
    return ImmutableList.copyOf(classNodes.values());
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy