/* * Copyright 2014 NAVER Corp. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.navercorp.pinpoint.profiler.objectfactory; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.ObjectFactory; import com.navercorp.pinpoint.bootstrap.plugin.ObjectFactory.ByConstructor; import com.navercorp.pinpoint.bootstrap.plugin.ObjectFactory.ByStaticFactoryMethod; import com.navercorp.pinpoint.exception.PinpointException; /** * @author Jongho Moon * */ public class AutoBindingObjectFactory { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final InstrumentContext pluginContext; private final ClassLoader classLoader; private final List<ArgumentProvider> commonProviders; public AutoBindingObjectFactory(ProfilerConfig profilerConfig, TraceContext traceContext, InstrumentContext pluginContext, ClassLoader classLoader, ArgumentProvider... argumentProviders) { if (profilerConfig == null) { throw new NullPointerException("profilerConfig must not be null"); } if (traceContext == null) { throw new NullPointerException("traceContext must not be null"); } if (pluginContext == null) { throw new NullPointerException("pluginContext must not be null"); } this.pluginContext = pluginContext; this.classLoader = classLoader; this.commonProviders = newArgumentProvider(profilerConfig, traceContext, pluginContext, argumentProviders); } private List<ArgumentProvider> newArgumentProvider(ProfilerConfig profilerConfig, TraceContext traceContext, InstrumentContext pluginContext, ArgumentProvider[] argumentProviders) { final List<ArgumentProvider> commonProviders = new ArrayList<ArgumentProvider>(); for (ArgumentProvider argumentProvider : argumentProviders) { commonProviders.add(argumentProvider); } ProfilerPluginArgumentProvider profilerPluginArgumentProvider = new ProfilerPluginArgumentProvider(profilerConfig, traceContext, pluginContext); commonProviders.add(profilerPluginArgumentProvider); return commonProviders; } public Object createInstance(ObjectFactory objectFactory, ArgumentProvider... providers) { final Class<?> type = pluginContext.injectClass(classLoader, objectFactory.getClassName()); final ArgumentsResolver argumentsResolver = getArgumentResolver(objectFactory, providers); if (objectFactory instanceof ByConstructor) { return byConstructor(type, (ByConstructor) objectFactory, argumentsResolver); } else if (objectFactory instanceof ByStaticFactoryMethod) { return byStaticFactoryMethod(type, (ByStaticFactoryMethod) objectFactory, argumentsResolver); } throw new IllegalArgumentException("Unknown objectFactory type: " + objectFactory); } private Object byConstructor(Class<?> type, ByConstructor byConstructor, ArgumentsResolver argumentsResolver) { final ConstructorResolver resolver = new ConstructorResolver(type, argumentsResolver); if (!resolver.resolve()) { throw new PinpointException("Cannot find suitable constructor for " + type.getName()); } final Constructor<?> constructor = resolver.getResolvedConstructor(); final Object[] resolvedArguments = resolver.getResolvedArguments(); if (isDebug) { logger.debug("Create instance by constructor {}, with arguments {}", constructor, Arrays.toString(resolvedArguments)); } try { return constructor.newInstance(resolvedArguments); } catch (Exception e) { throw new PinpointException("Fail to invoke constructor: " + constructor + ", arguments: " + Arrays.toString(resolvedArguments), e); } } private Object byStaticFactoryMethod(Class<?> type, ByStaticFactoryMethod staticFactoryMethod, ArgumentsResolver argumentsResolver) { StaticMethodResolver resolver = new StaticMethodResolver(type, staticFactoryMethod.getFactoryMethodName(), argumentsResolver); if (!resolver.resolve()) { throw new PinpointException("Cannot find suitable factory method " + type.getName() + "." + staticFactoryMethod.getFactoryMethodName()); } final Method method = resolver.getResolvedMethod(); final Object[] resolvedArguments = resolver.getResolvedArguments(); if (isDebug) { logger.debug("Create instance by static factory method {}, with arguments {}", method, Arrays.toString(resolvedArguments)); } try { return method.invoke(null, resolvedArguments); } catch (Exception e) { throw new PinpointException("Fail to invoke factory method: " + type.getName() + "." + staticFactoryMethod.getFactoryMethodName() + ", arguments: " + Arrays.toString(resolvedArguments), e); } } private ArgumentsResolver getArgumentResolver(ObjectFactory objectFactory, ArgumentProvider[] providers) { final List<ArgumentProvider> merged = new ArrayList<ArgumentProvider>(commonProviders); merged.addAll(Arrays.asList(providers)); if (objectFactory.getArguments() != null) { merged.add(new OrderedValueProvider(this, objectFactory.getArguments())); } return new ArgumentsResolver(merged); } }