    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
    015    package org.apache.tapestry5.ioc.internal;
    016
    017    import org.apache.tapestry5.ioc.*;
    018    import org.apache.tapestry5.ioc.def.ContributionDef3;
    019    import org.apache.tapestry5.ioc.internal.util.*;
    020    import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
    021    import org.slf4j.Logger;
    022
    023    import java.lang.reflect.InvocationTargetException;
    024    import java.lang.reflect.Method;
    025    import java.util.Map;
    026    import java.util.Set;
    027
    028    public 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        public boolean isOptional()
    063        {
    064            return optional;
    065        }
    066
    067        public String getServiceId()
    068        {
    069            return serviceId;
    070        }
    071
    072        public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources, Configuration configuration)
    073        {
    074            invokeMethod(moduleSource, resources, Configuration.class, configuration);
    075        }
    076
    077        public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources,
    078                               OrderedConfiguration configuration)
    079        {
    080            invokeMethod(moduleSource, resources, OrderedConfiguration.class, configuration);
    081        }
    082
    083        public void contribute(ModuleBuilderSource moduleSource, ServiceResources resources,
    084                               MappedConfiguration configuration)
    085        {
    086            invokeMethod(moduleSource, resources, MappedConfiguration.class, configuration);
    087        }
    088
    089        private <T> void invokeMethod(ModuleBuilderSource source, ServiceResources resources, Class<T> parameterType,
    090                                      T parameterValue)
    091        {
    092            Map<Class, Object> resourceMap = CollectionFactory.newMap();
    093
    094            resourceMap.put(parameterType, parameterValue);
    095            resourceMap.put(ObjectLocator.class, resources);
    096            resourceMap.put(Logger.class, resources.getLogger());
    097
    098            InjectionResources injectionResources = new MapInjectionResources(resourceMap);
    099
    100            // For each of the other configuration types that is not expected, add a guard.
    101
    102            for (Class t : CONFIGURATION_TYPES)
    103            {
    104                if (parameterType != t)
    105                {
    106                    injectionResources = new DelegatingInjectionResources(new WrongConfigurationTypeGuard(
    107                            resources.getServiceId(), t, parameterType), injectionResources);
    108                }
    109            }
    110
    111            Throwable fail = null;
    112
    113            Object moduleInstance = InternalUtils.isStatic(contributorMethod) ? null : source.getModuleBuilder();
    114
    115            try
    116            {
    117                ObjectCreator[] parameters = InternalUtils.calculateParametersForMethod(contributorMethod, resources,
    118                        injectionResources, resources.getTracker());
    119
    120                contributorMethod.invoke(moduleInstance, InternalUtils.realizeObjects(parameters));
    121            } catch (InvocationTargetException ex)
    122            {
    123                fail = ex.getTargetException();
    124            } catch (Exception ex)
    125            {
    126                fail = ex;
    127            }
    128
    129            if (fail != null)
    130                throw new RuntimeException(IOCMessages.contributionMethodError(contributorMethod, fail), fail);
    131        }
    132
    133        public Set<Class> getMarkers()
    134        {
    135            return markers;
    136        }
    137
    138        public Class getServiceInterface()
    139        {
    140            return serviceInterface;
    141        }
    142    }