/* * 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.plugin.httpclient3; import java.security.ProtectionDomain; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; /** * @author netspider * @author emeroad * @author minwoo.jung * @author jaehong.kim * */ public class HttpClient3Plugin implements ProfilerPlugin, TransformTemplateAware { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private TransformTemplate transformTemplate; @Override public void setup(ProfilerPluginSetupContext context) { final HttpClient3PluginConfig config = new HttpClient3PluginConfig(context.getConfig()); if (logger.isInfoEnabled()) { logger.info("HttpClient3Plugin config:{}", config); } // apache http client 3 addHttpClient3Class(); // apache http client 3 retry addDefaultHttpMethodRetryHandlerClass(); // 3.1.0 addHttpConnectionClass(); addHttpMethodBaseClass(config); } private void addHttpClient3Class() { transformTemplate.transform("org.apache.commons.httpclient.HttpClient", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumenttor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumenttor.getInstrumentClass(loader, className, classfileBuffer); injectHttpClientExecuteMethod(target, "org.apache.commons.httpclient.HttpMethod"); injectHttpClientExecuteMethod(target, "org.apache.commons.httpclient.HostConfiguration", "org.apache.commons.httpclient.HttpMethod"); injectHttpClientExecuteMethod(target, "org.apache.commons.httpclient.HostConfiguration", "org.apache.commons.httpclient.HttpMethod", "org.apache.commons.httpclient.HttpState"); return target.toBytecode(); } private void injectHttpClientExecuteMethod(InstrumentClass target, String... parameterTypeNames) throws InstrumentException { InstrumentMethod method = target.getDeclaredMethod("executeMethod", parameterTypeNames); if (method != null) { method.addInterceptor("com.navercorp.pinpoint.plugin.httpclient3.interceptor.ExecuteInterceptor"); } } }); } private void addDefaultHttpMethodRetryHandlerClass() { transformTemplate.transform("org.apache.commons.httpclient.DefaultHttpMethodRetryHandler", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); InstrumentMethod retryMethod = target.getDeclaredMethod("retryMethod", "org.apache.commons.httpclient.HttpMethod", "java.io.IOException", "int"); if (retryMethod != null) { retryMethod.addInterceptor("com.navercorp.pinpoint.plugin.httpclient3.interceptor.RetryMethodInterceptor"); } return target.toBytecode(); } }); } private void addHttpConnectionClass() { transformTemplate.transform("org.apache.commons.httpclient.HttpConnection", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); target.addGetter("com.navercorp.pinpoint.plugin.httpclient3.HostNameGetter", HttpClient3Constants.FIELD_HOST_NAME); target.addGetter("com.navercorp.pinpoint.plugin.httpclient3.PortNumberGetter", HttpClient3Constants.FIELD_PORT_NUMBER); target.addGetter("com.navercorp.pinpoint.plugin.httpclient3.ProxyHostNameGetter", HttpClient3Constants.FIELD_PROXY_HOST_NAME); target.addGetter("com.navercorp.pinpoint.plugin.httpclient3.ProxyPortNumberGetter", HttpClient3Constants.FIELD_PROXY_PORT_NUMBER); InstrumentMethod open = target.getDeclaredMethod("open"); if (open != null) { open.addInterceptor("com.navercorp.pinpoint.plugin.httpclient3.interceptor.HttpConnectionOpenMethodInterceptor"); } return target.toBytecode(); } }); } private void addHttpMethodBaseClass(final HttpClient3PluginConfig config) { transformTemplate.transform("org.apache.commons.httpclient.HttpMethodBase", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); InstrumentMethod execute = target.getDeclaredMethod("execute", "org.apache.commons.httpclient.HttpState", "org.apache.commons.httpclient.HttpConnection"); if (execute != null) { execute.addInterceptor("com.navercorp.pinpoint.plugin.httpclient3.interceptor.HttpMethodBaseExecuteMethodInterceptor"); } if (config.isIo()) { InstrumentMethod writeRequest = target.getDeclaredMethod("writeRequest", "org.apache.commons.httpclient.HttpState", "org.apache.commons.httpclient.HttpConnection"); if (writeRequest != null) { writeRequest.addInterceptor("com.navercorp.pinpoint.plugin.httpclient3.interceptor.HttpMethodBaseRequestAndResponseMethodInterceptor"); } InstrumentMethod readResponse = target.getDeclaredMethod("readResponse", "org.apache.commons.httpclient.HttpState", "org.apache.commons.httpclient.HttpConnection"); if (readResponse != null) { readResponse.addInterceptor("com.navercorp.pinpoint.plugin.httpclient3.interceptor.HttpMethodBaseRequestAndResponseMethodInterceptor"); } } return target.toBytecode(); } }); } @Override public void setTransformTemplate(TransformTemplate transformTemplate) { this.transformTemplate = transformTemplate; } }