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    }