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    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}