/* * Copyright © 2017 the original authors (http://cereebro.io) * * 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 io.cereebro.core; import java.util.Collection; import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.ToString; /** * Pictures a Component and how it relates to other. Within a System, there may * be different partial "views" of a given component depending on the * information available. * * @author michaeltecourt */ @ToString public class ComponentRelationships { private final Component component; private final Set<Dependency> dependencies; private final Set<Consumer> consumers; /** * Pictures a Component and how it relates to others. * * @param component * The documented component. * @param dependencies * Components that are depended upon by the documented component. * @param consumers * Components that rely on the documented component. */ @JsonCreator public ComponentRelationships(@JsonProperty("component") Component component, @JsonProperty("dependencies") Set<Dependency> dependencies, @JsonProperty("consumers") Set<Consumer> consumers) { this.component = Objects.requireNonNull(component, "Component required"); this.dependencies = new HashSet<>(dependencies); this.consumers = new HashSet<>(consumers); } /** * Pictures a Component and how it relates to others. * * @param component * The documented component. * @param dependencies * Components that are depended upon by the documented component. * @param consumers * Components that rely on the documented component. * @return ComponentRelationships */ public static ComponentRelationships of(Component component, Set<Dependency> dependencies, Set<Consumer> consumers) { return new ComponentRelationships(component, dependencies, consumers); } /** * Pictures a Component and how it relates to others. * * @param component * The documented component. * @param relationships * Relationship Collection that will be split between Dependency * and Consumer. * @return ComponentRelationships */ public static ComponentRelationships of(Component component, Collection<Relationship> relationships) { return new ComponentRelationships(component, filterDependencies(relationships), filterConsumers(relationships)); } /** * Extract {@link Consumer} objects out of a {@link Relationship} * collection. * * @param relationships * The relationships to filter. * @return Set of casted Consumer objects. */ public static Set<Consumer> filterConsumers(Collection<Relationship> relationships) { Objects.requireNonNull(relationships, "relationship collection required"); // @formatter:off return relationships.stream() .filter(rel -> rel instanceof Consumer) .map(rel -> (Consumer) rel) .collect(Collectors.toSet()); // @formatter:on } /** * Extract {@link Dependency} objects out of a {@link Relationship} * collection. * * @param relationships * The relationships to filter. * @return Set of Dependency objects. */ public static Set<Dependency> filterDependencies(Collection<Relationship> relationships) { Objects.requireNonNull(relationships, "relationship collection required"); // @formatter:off return relationships.stream() .filter(rel -> rel instanceof Dependency) .map(rel -> (Dependency) rel) .collect(Collectors.toSet()); // @formatter:on } /** * Tells if this component has some kind of relationship. * * @return {@code true} if consumers or dependencies are available, * {@code false} otherwise. */ public boolean hasRelationships() { return !getRelationships().isEmpty(); } @Override public int hashCode() { return Objects.hash(getClass(), component, dependencies, consumers); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || !getClass().equals(o.getClass())) { return false; } ComponentRelationships that = (ComponentRelationships) o; return Objects.equals(this.component, that.component) && Objects.equals(this.dependencies, that.dependencies) && Objects.equals(this.consumers, that.consumers); } /** * @return Component */ public Component getComponent() { return component; } /** * The components dependend upon by the component attribute. * * @return Dependency Set */ public Set<Dependency> getDependencies() { return new HashSet<>(dependencies); } /** * The component consuming the component. * * @return Consumer Set */ public Set<Consumer> getConsumers() { return new HashSet<>(consumers); } /** * All relationships at once. * * @return Both {@link Consumer} and {@link Dependency} relationships. */ @JsonIgnore public Set<Relationship> getRelationships() { return Stream.concat(dependencies.stream(), consumers.stream()).collect(Collectors.toSet()); } /** * Create a {@link ComponentRelationships} builder. * * @return new ComponentRelationshipsBuilder instance. */ public static ComponentRelationshipsBuilder builder() { return new ComponentRelationshipsBuilder(); } /** * {@link ComponentRelationships} Builder. * * @author michaeltecourt */ @ToString public static class ComponentRelationshipsBuilder { private Component component; private Set<Dependency> dependencies = new HashSet<>(); private Set<Consumer> consumers = new HashSet<>(); /** * Set the target component. * * @param component * The documented component. * @return this ComponentRelationshipsBuilder instance. */ public ComponentRelationshipsBuilder component(Component component) { this.component = Objects.requireNonNull(component, "component required"); return this; } /** * Overwrite the Dependency Set. * * @param dependencies * Dependencies that will overwrite the existing ones. * @return this ComponentRelationshipsBuilder instance. */ public ComponentRelationshipsBuilder dependencies(Collection<Dependency> dependencies) { Objects.requireNonNull(dependencies, "dependencies required"); this.dependencies = new HashSet<>(dependencies); return this; } /** * Overwrite the Consumer Set. * * @param consumers * Consumers that will overwrite the existing ones. * @return this ComponentRelationshipsBuilder instance. */ public ComponentRelationshipsBuilder consumers(Collection<Consumer> consumers) { Objects.requireNonNull(consumers, "consumers required"); this.consumers = new HashSet<>(consumers); return this; } /** * Add a Dependency to the existing set. * * @param dependency * Dependency to be added. * @return this ComponentRelationshipsBuilder instance. */ public ComponentRelationshipsBuilder addDependency(Dependency dependency) { this.dependencies.add(dependency); return this; } /** * Add a Consumer to the existing Set. * * @param consumer * Consumer to be added. * @return this ComponentRelationshipsBuilder instance. */ public ComponentRelationshipsBuilder addConsumer(Consumer consumer) { this.consumers.add(consumer); return this; } /** * Add all dependencies to the existing Set. * * @param dependencies * Collection of dependencies to be added. * @return this ComponentRelationshipsBuilder instance. */ public ComponentRelationshipsBuilder addDependencies(Collection<Dependency> dependencies) { this.dependencies.addAll(dependencies); return this; } /** * Add all consumers to the existing Set. * * @param consumers * Collection of consumers to be added. * @return this ComponentRelationshipsBuilder instance. */ public ComponentRelationshipsBuilder addConsumers(Collection<Consumer> consumers) { this.consumers.addAll(consumers); return this; } /** * Build an immutable {@link ComponentRelationships} object. * * @return ComponentRelationships */ public ComponentRelationships build() { return new ComponentRelationships(component, dependencies, consumers); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || !getClass().equals(o.getClass())) { return false; } ComponentRelationshipsBuilder that = (ComponentRelationshipsBuilder) o; return Objects.equals(this.component, that.component) && Objects.equals(this.dependencies, that.dependencies) && Objects.equals(this.consumers, that.consumers); } @Override public int hashCode() { return Objects.hash(getClass(), component, dependencies, consumers); } } }