com.google.security.fences.inheritance.InheritanceGraph Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fences-maven-enforcer-rule Show documentation
Show all versions of fences-maven-enforcer-rule Show documentation
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.
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 extends String> newInterfaceNames) {
this.interfaceNames.addAll(newInterfaceNames);
return this;
}
/** Sets the list of declared methods. */
public DeclarationBuilder methods(
Iterable extends MethodDetails> newMethods) {
this.methods.addAll(newMethods);
return this;
}
/** Sets the list of declared fields. */
public DeclarationBuilder fields(
Iterable extends FieldDetails> 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