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