/* * Copyright 2017 TNG Technology Consulting GmbH * * 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. */ package com.tngtech.archunit.core.domain; import java.util.Objects; import com.tngtech.archunit.Internal; import com.tngtech.archunit.PublicAPI; import com.tngtech.archunit.base.ChainableFunction; import com.tngtech.archunit.base.DescribedPredicate; import com.tngtech.archunit.core.domain.properties.HasDescription; import com.tngtech.archunit.core.domain.properties.HasName; import com.tngtech.archunit.core.domain.properties.HasOwner; import com.tngtech.archunit.core.domain.properties.HasOwner.Functions.Get; import com.tngtech.archunit.core.importer.DomainBuilders; import static com.google.common.base.Preconditions.checkNotNull; import static com.tngtech.archunit.PublicAPI.Usage.ACCESS; import static com.tngtech.archunit.core.domain.Formatters.formatLocation; public abstract class JavaAccess<TARGET extends AccessTarget> implements HasName, HasDescription, HasOwner<JavaCodeUnit> { private final JavaCodeUnit origin; private final TARGET target; private final int lineNumber; private final int hashCode; JavaAccess(DomainBuilders.JavaAccessBuilder<TARGET, ?> builder) { this.origin = checkNotNull(builder.getOrigin()); this.target = checkNotNull(builder.getTarget()); this.lineNumber = builder.getLineNumber(); this.hashCode = Objects.hash(origin.getFullName(), target.getFullName(), lineNumber); } @Override public String getName() { return target.getName(); } @PublicAPI(usage = ACCESS) public JavaCodeUnit getOrigin() { return origin; } @PublicAPI(usage = ACCESS) public JavaClass getOriginOwner() { return getOrigin().getOwner(); } @PublicAPI(usage = ACCESS) public JavaClass getTargetOwner() { return getTarget().getOwner(); } @PublicAPI(usage = ACCESS) public TARGET getTarget() { return target; } @PublicAPI(usage = ACCESS) public int getLineNumber() { return lineNumber; } @Override public JavaCodeUnit getOwner() { return getOrigin(); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } final JavaAccess<?> other = (JavaAccess<?>) obj; return Objects.equals(this.origin.getFullName(), other.origin.getFullName()) && Objects.equals(this.target.getFullName(), other.target.getFullName()) && Objects.equals(this.lineNumber, other.lineNumber); } @Override public String toString() { return getClass().getSimpleName() + "{origin=" + origin + ", target=" + target + ", lineNumber=" + lineNumber + additionalToStringFields() + '}'; } String additionalToStringFields() { return ""; } @Override public String getDescription() { return getDescriptionWithTemplate(descriptionTemplate()); } @Internal public String getDescriptionWithTemplate(String template) { String description = String.format(template, getOwner().getFullName(), getTarget().getFullName()); String location = formatLocation(getLocationClass(), getLineNumber()); return String.format("%s in %s", description, location); } private JavaClass getLocationClass() { JavaClass location = getOriginOwner(); while (location.getEnclosingClass().isPresent()) { location = location.getEnclosingClass().get(); } return location; } protected abstract String descriptionTemplate(); public static final class Predicates { private Predicates() { } @PublicAPI(usage = ACCESS) public static DescribedPredicate<JavaAccess<?>> originOwner(DescribedPredicate<? super JavaClass> predicate) { return origin(Get.<JavaClass>owner().is(predicate)); } @PublicAPI(usage = ACCESS) public static DescribedPredicate<JavaAccess<?>> origin(DescribedPredicate<? super JavaCodeUnit> predicate) { return predicate.onResultOf(Functions.Get.origin()).as("origin " + predicate.getDescription()); } @PublicAPI(usage = ACCESS) public static DescribedPredicate<JavaAccess<?>> originOwnerEqualsTargetOwner() { return new DescribedPredicate<JavaAccess<?>>("origin owner equals target owner") { @Override public boolean apply(JavaAccess<?> input) { return input.getOriginOwner().equals(input.getTargetOwner()); } }; } @PublicAPI(usage = ACCESS) public static DescribedPredicate<JavaAccess<?>> targetOwner(final DescribedPredicate<? super JavaClass> predicate) { return target(Get.<JavaClass>owner().is(predicate)); } @PublicAPI(usage = ACCESS) public static DescribedPredicate<JavaAccess<?>> target(final DescribedPredicate<? super AccessTarget> predicate) { return new DescribedPredicate<JavaAccess<?>>("target " + predicate.getDescription()) { @Override public boolean apply(JavaAccess<?> input) { return predicate.apply(input.getTarget()); } }; } } @PublicAPI(usage = ACCESS) public static final class Functions { private Functions() { } public static final class Get { private Get() { } @PublicAPI(usage = ACCESS) public static ChainableFunction<JavaAccess<?>, JavaCodeUnit> origin() { return new ChainableFunction<JavaAccess<?>, JavaCodeUnit>() { @Override public JavaCodeUnit apply(JavaAccess<?> input) { return input.getOrigin(); } }; } @PublicAPI(usage = ACCESS) public static <A extends JavaAccess<? extends T>, T extends AccessTarget> ChainableFunction<A, T> target() { return new ChainableFunction<A, T>() { @Override public T apply(A input) { return input.getTarget(); } }; } } } }