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}