// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.component.chain; import com.yahoo.component.ComponentId; import com.yahoo.component.chain.dependencies.ordering.ChainBuilder; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; /** * An immutable ordered list of components * * @author Tony Vaagenes */ public class Chain { final private List componentList; private final ComponentId id; /** Create a chain directly. This will NOT order the chain by the ordering constraints. */ public Chain(String id, List componentList) { this(new ComponentId(id), componentList); } /** Create a chain directly. This will NOT order the chain by the ordering constraints. */ public Chain(ComponentId id, List componentList) { this.id = id; this.componentList = List.copyOf(componentList); } /** Create a chain directly. This will NOT order the chain by the ordering constraints. */ public Chain(List componentList) { this(new ComponentId("anonymous chain"), componentList); } /** Create a chain directly. This will NOT order the chain by the ordering constraints. */ @SafeVarargs public Chain(COMPONENT... components) { this("anonymous chain", components); } /** Create a chain directly. This will NOT order the chain by the ordering constraints. */ @SafeVarargs public Chain(String id, COMPONENT... components) { this(new ComponentId(id), components); } /** Create a chain directly. This will NOT order the chain by the ordering constraints. */ @SafeVarargs @SuppressWarnings("varargs") public Chain(ComponentId id, COMPONENT... components) { this(id, Arrays.asList(components)); } /** Create a chain by using a builder. This will order the chain by the ordering constraints. */ public Chain(ComponentId id, Collection components, Collection phases) { this(id, buildChain( emptyListIfNull(components), emptyListIfNull(phases)).components()); } public ComponentId getId() { return id; } private static Collection emptyListIfNull(Collection collection) { return collection == null ? Collections.emptyList() : collection; } private static Chain buildChain(Collection components, Collection phases) { ChainBuilder builder = new ChainBuilder<>(new ComponentId("temp")); for (Phase phase : phases) { builder.addPhase(phase); } for (T component : components) { builder.addComponent(component); } return builder.orderNodes(); } public List components() { return componentList; } public @Override String toString() { StringBuilder b = new StringBuilder("chain '"); b.append(getId().stringValue()); b.append("' ["); appendComponent(0, b); appendComponent(1, b); if (components().size() > 3) b.append("... -> "); if (components().size() > 2) appendComponent(components().size() - 1, b); b.append("]"); return b.toString(); } private void appendComponent(int i, StringBuilder b) { if (i >= components().size()) return; b.append(components().get(i).getId().stringValue()); if (i < components().size() - 1) b.append(" -> "); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Chain chain = (Chain) o; if (!componentList.equals(chain.componentList)) return false; if (!id.equals(chain.id)) return false; return true; } @Override public int hashCode() { int result = componentList.hashCode(); result = 31 * result + id.hashCode(); return result; } }