001 // Copyright 2006, 2007, 2008, 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 015 package org.apache.tapestry5.ioc.internal.services; 016 017 import java.lang.reflect.Method; 018 import java.util.Map; 019 020 import org.apache.tapestry5.ioc.services.Builtin; 021 import org.apache.tapestry5.ioc.services.PlasticProxyFactory; 022 import org.apache.tapestry5.ioc.services.StrategyBuilder; 023 import org.apache.tapestry5.ioc.util.StrategyRegistry; 024 import org.apache.tapestry5.plastic.ClassInstantiator; 025 import org.apache.tapestry5.plastic.InstructionBuilder; 026 import org.apache.tapestry5.plastic.InstructionBuilderCallback; 027 import org.apache.tapestry5.plastic.MethodDescription; 028 import org.apache.tapestry5.plastic.PlasticClass; 029 import org.apache.tapestry5.plastic.PlasticClassTransformer; 030 import org.apache.tapestry5.plastic.PlasticField; 031 032 public class StrategyBuilderImpl implements StrategyBuilder 033 { 034 private final PlasticProxyFactory proxyFactory; 035 036 public StrategyBuilderImpl(@Builtin 037 PlasticProxyFactory proxyFactory) 038 { 039 this.proxyFactory = proxyFactory; 040 } 041 042 public <S> S build(StrategyRegistry<S> registry) 043 { 044 return createProxy(registry.getAdapterType(), registry); 045 } 046 047 public <S> S build(Class<S> adapterType, Map<Class, S> registrations) 048 { 049 StrategyRegistry<S> registry = StrategyRegistry.newInstance(adapterType, registrations); 050 051 return build(registry); 052 } 053 054 private <S> S createProxy(final Class<S> interfaceType, final StrategyRegistry<S> registry) 055 { 056 ClassInstantiator instantiator = proxyFactory.createProxy(interfaceType, new PlasticClassTransformer() 057 { 058 public void transform(PlasticClass plasticClass) 059 { 060 final PlasticField registryField = plasticClass.introduceField(StrategyRegistry.class, "registry") 061 .inject(registry); 062 063 for (final Method method : interfaceType.getMethods()) 064 { 065 plasticClass.introduceMethod(new MethodDescription(method), new InstructionBuilderCallback() 066 { 067 public void doBuild(InstructionBuilder builder) 068 { 069 Class returnType = method.getReturnType(); 070 071 builder.loadThis().getField(registryField); 072 073 // Argument 0 is the selector used to find the adapter and should be an object reference, 074 // not a primitive. 075 076 builder.loadArgument(0); 077 078 // Use the StrategyRegistry to get the adapter to re-invoke the method on 079 builder.invoke(StrategyRegistry.class, Object.class, "getByInstance", Object.class) 080 .checkcast(interfaceType); 081 082 // That leaves the correct adapter on top of the stack. Get the 083 // selector and the rest of the arguments in place and invoke the method. 084 085 builder.loadArguments().invoke(interfaceType, returnType, method.getName(), 086 method.getParameterTypes()); 087 088 builder.returnResult(); 089 } 090 }); 091 } 092 093 plasticClass.addToString(String.format("<Strategy for %s>", interfaceType.getName())); 094 } 095 }); 096 097 return interfaceType.cast(instantiator.newInstance()); 098 } 099 }