    001// Copyright 2006, 2007, 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;
    016
    017import org.apache.tapestry5.ioc.*;
    018import org.apache.tapestry5.ioc.def.ContributionDef3;
    019import org.apache.tapestry5.ioc.internal.util.*;
    020import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
    021import org.slf4j.Logger;
    022
    023import java.lang.reflect.InvocationTargetException;
    024import java.lang.reflect.Method;
    025import java.util.Map;
    026import java.util.Set;
    027
    028public class ContributionDefImpl implements ContributionDef3
    029{
    030    private final String serviceId;
    031
    032    private final Method contributorMethod;
    033
    034    private final boolean optional;
    035
    036    private final PlasticProxyFactory proxyFactory;
    037
    038    private final Set<Class> markers;
    039
    040    private final Class serviceInterface;
    041
    042    private static final Class[] CONFIGURATION_TYPES = new Class[]
    043            {Configuration.class, MappedConfiguration.class, OrderedConfiguration.class};
    044
    045    public ContributionDefImpl(String serviceId, Method contributorMethod, boolean optional, PlasticProxyFactory proxyFactory,
    046                               Class serviceInterface, Set<Class> markers)
    047    {
    048        this.serviceId = serviceId;
    049        this.contributorMethod = contributorMethod;
    050        this.optional = optional;
    051        this.proxyFactory = proxyFactory;
    052        this.serviceInterface = serviceInterface;
    053        this.markers = markers;
    054    }
    055
    056    @Override
    057    public String toString()
    058    {
    059        return InternalUtils.asString(contributorMethod, proxyFactory);
    060    }
    061
    062    @Override
    063    public boolean isOptional()
    064    {
    065        return optional;
    066    }
    067
    068    @Override
    069    public String getServiceId()
    070    {
    071        return serviceId;
    072    }
    073
    074    @Override
    075    public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources, Configuration configuration)
    076    {
    077        invokeMethod(moduleSource, resources, Configuration.class, configuration);
    078    }
    079
    080    @Override
    081    public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources,
    082                           OrderedConfiguration configuration)
    083    {
    084        invokeMethod(moduleSource, resources, OrderedConfiguration.class, configuration);
    085    }
    086
    087    @Override
    088    public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources,
    089                           MappedConfiguration configuration)
    090    {
    091        invokeMethod(moduleSource, resources, MappedConfiguration.class, configuration);
    092    }
    093
    094    private <T> void invokeMethod(ModuleBuilderSource source, ServiceResources resources, Class<T> parameterType,
    095                                  T parameterValue)
    096    {
    097        Map<Class, Object> resourceMap = CollectionFactory.newMap();
    098
    099        resourceMap.put(parameterType, parameterValue);
    100        resourceMap.put(ObjectLocator.class, resources);
    101        resourceMap.put(Logger.class, resources.getLogger());
    102
    103        InjectionResources injectionResources = new MapInjectionResources(resourceMap);
    104
    105        // For each of the other configuration types that is not expected, add a guard.
    106
    107        for (Class t : CONFIGURATION_TYPES)
    108        {
    109            if (parameterType != t)
    110            {
    111                injectionResources = new DelegatingInjectionResources(new WrongConfigurationTypeGuard(
    112                        resources.getServiceId(), t, parameterType), injectionResources);
    113            }
    114        }
    115
    116        Throwable fail = null;
    117
    118        Object moduleInstance = InternalUtils.isStatic(contributorMethod) ? null : source.getModuleBuilder();
    119
    120        try
    121        {
    122            ObjectCreator[] parameters = InternalUtils.calculateParametersForMethod(contributorMethod, resources,
    123                    injectionResources, resources.getTracker());
    124
    125            contributorMethod.invoke(moduleInstance, InternalUtils.realizeObjects(parameters));
    126        } catch (InvocationTargetException ex)
    127        {
    128            fail = ex.getTargetException();
    129        } catch (Exception ex)
    130        {
    131            fail = ex;
    132        }
    133
    134        if (fail != null)
    135            throw new RuntimeException(IOCMessages.contributionMethodError(contributorMethod, fail), fail);
    136    }
    137
    138    @Override
    139    public Set<Class> getMarkers()
    140    {
    141        return markers;
    142    }
    143
    144    @Override
    145    public Class getServiceInterface()
    146    {
    147        return serviceInterface;
    148    }
    149}