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

com.google.security.fences.config.ClassNameDisambiguator 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.config;

import com.google.common.base.Optional;
import com.google.security.fences.inheritance.ClassNode;
import com.google.security.fences.inheritance.InheritanceGraph;
import com.google.security.fences.policy.ApiElement;
import com.google.security.fences.policy.ApiElementType;

/**
 * Resolves ambiguity between
 * 
 * class Foo {
 *   class Bar {
 *     ...
 *   }
 * }
* and *
 * class Foo$Bar { ... }
 * 
* by looking up classes in the inheritance graph derived from the class path. */ final class ClassNameDisambiguator { private final InheritanceGraph g; private final String partiallyQualifiedName; ClassNameDisambiguator(InheritanceGraph g, String partiallyQualifiedName) { this.g = g; this.partiallyQualifiedName = partiallyQualifiedName; } Optional resolve(ApiElement parent) { return resolve(parent, 0, 0); } private Optional resolve( ApiElement parent, int nameStartIndex, int nameIndex) { ApiElementType parentType = parent.type; int n = partiallyQualifiedName.length(); if (nameIndex == n) { if (nameStartIndex == nameIndex) { if (parentType == ApiElementType.CLASS) { return Optional.of(parent); } } else { char boundaryType = nameStartIndex >= 0 ? partiallyQualifiedName.charAt(nameStartIndex - 1) : '.'; if (boundaryType == '$' || boundaryType == '.') { String name = partiallyQualifiedName.substring( nameStartIndex + 1, nameIndex); return Optional.of(parent.child(name, ApiElementType.CLASS)); } } return Optional.absent(); } int nameEndIndex; boolean canBeClassBoundary = true; boolean canBePackageBoundary = false; boolean optional = false; for (nameEndIndex = nameIndex; ++nameEndIndex < n;) { // By pre-incrementing we ensure that there is never an empty identifier // to the left of the split-point, and by checking here, we ensure that // there is never an empty identifier to the right of the split point. if (nameEndIndex + 1 == n) { continue; } char ch = partiallyQualifiedName.charAt(nameEndIndex); if (ch == '.') { canBeClassBoundary = canBePackageBoundary = true; optional = false; break; } else if (ch == '$') { canBeClassBoundary = true; canBePackageBoundary = false; optional = true; break; } else if (ch == '/') { canBeClassBoundary = false; canBePackageBoundary = true; optional = false; break; } } if (optional && nameEndIndex < n && nameEndIndex != nameIndex) { // Bias towards longer names since the split version can always be // specified in a with more elements as in // // Foo // // Bar // // // but there is only one way to specify a class with a `$` in its name: // Foo$Bar... Optional longerOption = resolve( parent, nameStartIndex, nameEndIndex); if (longerOption.isPresent()) { return longerOption; } } String partName = partiallyQualifiedName.substring( nameStartIndex, nameEndIndex); if (partName.indexOf('/') >= 0 || partName.indexOf('.') >= 0) { return Optional.absent(); } int nextStartIndex = nameEndIndex < n ? nameEndIndex + 1 : nameEndIndex; // Bias towards packages. // foo.bar.baz -> foo/bar/baz // instead of // foo/bar$baz // for no particular reason. if (canBePackageBoundary && nameEndIndex < n) { ApiElement newParent = parent.child(partName, ApiElementType.PACKAGE); Optional packageOption = resolve( newParent, nextStartIndex, nextStartIndex); if (packageOption.isPresent()) { return packageOption; } } if (canBeClassBoundary) { ApiElement newParent = parent.child(partName, ApiElementType.CLASS); // This allows us to deal with unambiguously specified provided // dependencies. Optional classNode = g.named(newParent.toInternalName()); if (classNode.isPresent() && isContainedIn(classNode.get(), parent)) { Optional classOption = resolve( newParent, nextStartIndex, nextStartIndex); if (classOption.isPresent()) { return classOption; } } } // Handle unambiguous provided dependencies. if (nameStartIndex == 0 && nameEndIndex == n && partiallyQualifiedName.indexOf('/') < 0 && partiallyQualifiedName.indexOf('.') < 0 && partiallyQualifiedName.indexOf('$') < 0) { return Optional.of( parent.child(partiallyQualifiedName, ApiElementType.CLASS)); } return Optional.absent(); } private static boolean isContainedIn(ClassNode inner, ApiElement outer) { Optional outerClass = inner.outerClass; if (outer.type == ApiElementType.PACKAGE) { return !outerClass.isPresent(); } if (outerClass.isPresent()) { return outer.toInternalName().equals(outerClass.get()); } return false; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy