001// Copyright 2026 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.ioc.internal.services; 016 017import java.util.ArrayList; 018import java.util.List; 019 020/** 021 * Describes an assembled pipeline as {@code header: filter -> filter -> terminator}. 022 * 023 * <p>The {@code toString()} of the bridge classes generated by {@link BridgeBuilder} delegates here, 024 * as does {@link org.apache.tapestry5.ioc.services.AssembledPipeline}. 025 * @since 5.9.2 026 */ 027public final class PipelineDescriber 028{ 029 private static final String SEPARATOR = " -> "; 030 031 private PipelineDescriber() 032 { 033 } 034 035 /** 036 * The header identifying a pipeline, ahead of its steps. 037 */ 038 public static String header(Class<?> serviceInterface, Class<?> filterInterface) 039 { 040 return String.format("<PipelineBridge from %s to %s>", serviceInterface.getName(), filterInterface.getName()); 041 } 042 043 /** 044 * Walks the pipeline from the given step to its end, describing each filter, including the terminator. 045 * 046 * @param header 047 * identifies the pipeline, the steps follow it, separated by a colon 048 * @param step 049 * where to start, typically the outermost bridge, but any step describes the pipeline from itself 050 * onwards 051 */ 052 public static String describe(String header, PipelineStep step) 053 { 054 List<Object> steps = new ArrayList<>(); 055 056 Object current = step; 057 058 while (current instanceof PipelineStep) 059 { 060 PipelineStep pipelineStep = (PipelineStep) current; 061 062 steps.add(pipelineStep.getPipelineFilter()); 063 064 current = pipelineStep.getPipelineNext(); 065 } 066 067 steps.add(current); 068 069 return describe(header, steps); 070 } 071 072 /** 073 * Describes steps that have already been collected: the filters, in the order they are invoked, followed by the 074 * terminator. 075 */ 076 public static String describe(String header, List<?> steps) 077 { 078 StringBuilder builder = new StringBuilder(header).append(": "); 079 080 for (int i = 0; i < steps.size(); i++) 081 { 082 if (i > 0) 083 { 084 builder.append(SEPARATOR); 085 } 086 087 builder.append(steps.get(i)); 088 } 089 090 return builder.toString(); 091 } 092}