001// Copyright 2006, 2007, 2011 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.Collections; 019import java.util.List; 020 021import org.apache.tapestry5.commons.services.PlasticProxyFactory; 022import org.apache.tapestry5.commons.util.CollectionFactory; 023import org.apache.tapestry5.ioc.services.AssembledPipeline; 024import org.apache.tapestry5.ioc.services.Builtin; 025import org.apache.tapestry5.ioc.services.DefaultImplementationBuilder; 026import org.apache.tapestry5.ioc.services.PipelineBuilder; 027import org.slf4j.Logger; 028 029public class PipelineBuilderImpl implements PipelineBuilder 030{ 031 032 private final PlasticProxyFactory proxyFactory; 033 034 private final DefaultImplementationBuilder defaultImplementationBuilder; 035 036 private final List<AssembledPipeline> assembledPipelines = CollectionFactory.newThreadSafeList(); 037 038 public PipelineBuilderImpl(@Builtin 039 PlasticProxyFactory proxyFactory, 040 041 DefaultImplementationBuilder defaultImplementationBuilder) 042 { 043 this.proxyFactory = proxyFactory; 044 this.defaultImplementationBuilder = defaultImplementationBuilder; 045 } 046 047 @Override 048 public <S, F> S build(Logger logger, Class<S> serviceInterface, Class<F> filterInterface, List<F> filters) 049 { 050 S terminator = defaultImplementationBuilder.createDefaultImplementation(serviceInterface); 051 052 return build(logger, serviceInterface, filterInterface, filters, terminator); 053 } 054 055 @Override 056 public <S, F> S build(Logger logger, Class<S> serviceInterface, Class<F> filterInterface, List<F> filters, 057 S terminator) 058 { 059 track(serviceInterface, filterInterface, filters, terminator); 060 061 if (filters.isEmpty()) 062 return terminator; 063 064 BridgeBuilder<S, F> bb = new BridgeBuilder<S, F>(logger, serviceInterface, filterInterface, proxyFactory); 065 066 // The first bridge will point to the terminator. 067 // Like service decorators, we work deepest (last) 068 // to shallowest (first) 069 070 S next = terminator; 071 int count = filters.size(); 072 073 for (int i = count - 1; i >= 0; i--) 074 { 075 F filter = filters.get(i); 076 077 next = bb.instantiateBridge(next, filter); 078 } 079 080 if (logger.isDebugEnabled()) 081 { 082 logger.debug("Assembled pipeline: {}", next); 083 } 084 085 return next; 086 } 087 088 @Override 089 public List<AssembledPipeline> getAssembledPipelines() 090 { 091 return Collections.unmodifiableList(assembledPipelines); 092 } 093 094 /** 095 * Records the pipeline for later introspection, describing the filters and the terminator as they are now rather 096 * than holding on to them. 097 */ 098 private <S, F> void track(Class<S> serviceInterface, Class<F> filterInterface, List<F> filters, S terminator) 099 { 100 List<String> descriptions = new ArrayList<>(filters.size()); 101 102 for (F filter : filters) 103 { 104 descriptions.add(String.valueOf(filter)); 105 } 106 107 assembledPipelines.add(new AssembledPipeline(serviceInterface, filterInterface, descriptions, 108 String.valueOf(terminator))); 109 } 110 111}