001    // Copyright 2009 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.ModuleBuilderSource;
018    import org.apache.tapestry5.ioc.ObjectLocator;
019    import org.apache.tapestry5.ioc.OperationTracker;
020    import org.apache.tapestry5.ioc.ServiceResources;
021    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
022    import org.apache.tapestry5.ioc.internal.util.InjectionResources;
023    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
024    import org.apache.tapestry5.ioc.services.ClassFactory;
025    import org.slf4j.Logger;
026    
027    import java.lang.reflect.InvocationTargetException;
028    import java.lang.reflect.Method;
029    import java.util.Map;
030    
031    /**
032     * Based class for service decorators and service advisors that work by invoking a module method.
033     *
034     * @since 5.1.0.0
035     */
036    public class AbstractMethodInvokingInstrumenter
037    {
038        private final ModuleBuilderSource moduleSource;
039    
040        protected final Map<Class, Object> resourcesDefaults = CollectionFactory.newMap();
041    
042        private final ServiceResources resources;
043    
044        private final ClassFactory classFactory;
045    
046        protected final Method method;
047    
048        protected final Class serviceInterface;
049    
050        protected final String serviceId;
051        private final Logger logger;
052    
053        public AbstractMethodInvokingInstrumenter(
054                ModuleBuilderSource moduleSource, Method method, ServiceResources resources, ClassFactory classFactory)
055        {
056            this.moduleSource = moduleSource;
057            this.method = method;
058            this.resources = resources;
059            this.classFactory = classFactory;
060    
061            serviceId = resources.getServiceId();
062    
063            resourcesDefaults.put(String.class, serviceId);
064            resourcesDefaults.put(ObjectLocator.class, resources);
065            resourcesDefaults.put(ServiceResources.class, resources);
066            logger = resources.getLogger();
067            resourcesDefaults.put(Logger.class, logger);
068            serviceInterface = resources.getServiceInterface();
069            resourcesDefaults.put(Class.class, serviceInterface);
070            resourcesDefaults.put(OperationTracker.class, resources.getTracker());
071        }
072    
073        @Override
074        public String toString()
075        {
076            return classFactory.getMethodLocation(method).toString();
077        }
078    
079        private Object getModuleInstance()
080        {
081            return InternalUtils.isStatic(method)
082                   ? null
083                   : moduleSource.getModuleBuilder();
084        }
085    
086        protected Object invoke(InjectionResources injectionResources)
087        {
088            Object result = null;
089            Throwable failure = null;
090    
091            if (logger.isDebugEnabled())
092                logger.debug(String.format("Invoking method %s", this));
093    
094            try
095            {
096                Object[] parameters = InternalUtils.calculateParametersForMethod(
097                        method,
098                        resources,
099                        injectionResources, resources.getTracker());
100    
101                result = method.invoke(getModuleInstance(), parameters);
102            }
103            catch (InvocationTargetException ite)
104            {
105                failure = ite.getTargetException();
106            }
107            catch (Exception ex)
108            {
109                failure = ex;
110            }
111    
112            if (failure != null)
113                throw new RuntimeException(
114                        String.format("Exception invoking method %s: %s",
115                                      this,
116                                      InternalUtils.toMessage(failure)),
117                        failure);
118    
119            return result;
120        }
121    }