    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}