001// Copyright 2008, 2009, 2010, 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 org.apache.tapestry5.beanmodel.services.PlasticProxyFactoryImpl;
018import org.apache.tapestry5.commons.services.PlasticProxyFactory;
019import org.apache.tapestry5.commons.util.CollectionFactory;
020import org.apache.tapestry5.ioc.AnnotationAccess;
021import org.apache.tapestry5.plastic.InstructionBuilder;
022import org.apache.tapestry5.plastic.InstructionBuilderCallback;
023import org.apache.tapestry5.plastic.MethodDescription;
024import org.apache.tapestry5.plastic.PlasticClass;
025import org.apache.tapestry5.plastic.PlasticClassTransformation;
026import org.apache.tapestry5.plastic.PlasticField;
027
028import java.lang.reflect.Method;
029import java.lang.reflect.Modifier;
030import java.util.Arrays;
031import java.util.Set;
032
033@SuppressWarnings("all")
034public class AspectInterceptorBuilderImpl<T> extends AbtractAspectInterceptorBuilder<T>
035{
036    private final Class<T> serviceInterface;
037
038    private final Set<Method> allMethods = CollectionFactory.newSet();
039
040    private final PlasticClassTransformation transformation;
041
042    private final PlasticClass plasticClass;
043
044    public AspectInterceptorBuilderImpl(AnnotationAccess annotationAccess, PlasticProxyFactory plasticProxyFactory,
045                                        Class<T> serviceInterface, T delegate, String description)
046    {
047        super(annotationAccess);
048
049        this.serviceInterface = serviceInterface;
050
051        final Class<? extends Object> delegateType = delegate.getClass();
052        transformation = plasticProxyFactory.createProxyTransformation(serviceInterface, (Class<? extends T>) delegateType);
053        plasticClass = transformation.getPlasticClass();
054
055        plasticClass.addToString(description);
056
057        allMethods.addAll(Arrays.asList(serviceInterface.getMethods()));
058
059        final PlasticField delegateField = plasticClass.introduceField(serviceInterface, "delegate").inject(delegate);
060
061        for (Method method : allMethods)
062        {
063            if (!Modifier.isStatic(method.getModifiers()))
064            {
065                plasticClass.introduceMethod(method).delegateTo(delegateField);
066            }
067        }
068        
069        // TAP5-2235
070        final String delegateTypeName = delegateType.getName();
071        MethodDescription getDelegateMethodDescription = 
072                new MethodDescription(delegateTypeName, PlasticProxyFactoryImpl.INTERNAL_GET_DELEGATE);
073        plasticClass.introduceMethod(getDelegateMethodDescription, new InstructionBuilderCallback()
074        {
075            @Override
076            public void doBuild(InstructionBuilder builder)
077            {
078                builder.loadThis().getField(delegateField);
079                builder.checkcast(delegateType).returnResult();
080            }
081        });
082    }
083
084    @Override
085    public void adviseMethod(Method method, org.apache.tapestry5.plastic.MethodAdvice advice)
086    {
087        assert method != null;
088        assert advice != null;
089
090        if (!allMethods.contains(method))
091            throw new IllegalArgumentException(String.format("Method %s is not defined for interface %s.", method,
092                    serviceInterface));
093
094        plasticClass.introduceMethod(method).addAdvice(advice);
095    }
096
097    @Override
098    public void adviseAllMethods(org.apache.tapestry5.plastic.MethodAdvice advice)
099    {
100        for (Method m : serviceInterface.getMethods())
101        {
102            // TAP5-2667
103            if (!Modifier.isStatic(m.getModifiers()))
104            {
105                adviseMethod(m, advice);
106            }
107        }
108    }
109
110    @Override
111    public Class getInterface()
112    {
113        return serviceInterface;
114    }
115
116    @Override
117    public T build()
118    {
119        return (T) transformation.createInstantiator().newInstance();
120    }
121}