/* * 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.instrument.interceptor; import java.lang.reflect.Method; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; /** * @author Jongho Moon * */ public class InvokeAfterCodeGenerator extends InvokeCodeGenerator { private static final int THIS_RETURN_EXCEPTION_SIZE = 3; private final int interceptorId; private final InterceptorDefinition interceptorDefinition; private final InstrumentClass targetClass; private final boolean localVarsInitialized; private final boolean catchClause; public InvokeAfterCodeGenerator(int interceptorId, InterceptorDefinition interceptorDefinition, InstrumentClass targetClass, InstrumentMethod targetMethod, ApiMetaDataService apiMetaDataService, boolean localVarsInitialized, boolean catchClause) { super(interceptorId, interceptorDefinition, targetMethod, apiMetaDataService); this.interceptorDefinition = interceptorDefinition; this.interceptorId = interceptorId; this.targetClass = targetClass; this.localVarsInitialized = localVarsInitialized; this.catchClause = catchClause; } public String generate() { final CodeBuilder builder = new CodeBuilder(); builder.begin(); // try { // (($INTERCEPTOR_TYPE)_$PINPOINT$_holder13.getInterceptor.before($ARGUMENTS); // } catch (Throwable t) { // InterceptorInvokerHelper.handleException(t); // } // // throw e; builder.append("try { "); if (!localVarsInitialized) { builder.format("%1$s = %2$s.getInterceptor(%3$d); ", getInterceptorVar(), getInterceptorRegistryClassName(), interceptorId); } final Method afterMethod = interceptorDefinition.getAfterMethod(); if (afterMethod != null) { builder.format("((%1$s)%2$s).after(", getInterceptorType(), getInterceptorVar()); appendArguments(builder); builder.format(");"); } builder.format("} catch (java.lang.Throwable _$PINPOINT_EXCEPTION$_) { %1$s.handleException(_$PINPOINT_EXCEPTION$_); }", getInterceptorInvokerHelperClassName()); if (catchClause) { builder.append(" throw $e;"); } builder.end(); return builder.toString(); } private String getReturnValue() { if (catchClause) { return "null"; } if (!targetMethod.isConstructor()) { if ("void".equals(targetMethod.getReturnType())) { return "null"; } } return "($w)$_"; } private String getException() { if (catchClause) { return "$e"; } return "null"; } private void appendArguments(CodeBuilder builder) { final InterceptorType type = interceptorDefinition.getInterceptorType(); switch (type) { case ARRAY_ARGS: appendSimpleAfterArguments(builder); break; case STATIC: appendStaticAfterArguments(builder); break; case API_ID_AWARE: appendApiIdAwareAfterArguments(builder); break; case BASIC: appendCustomAfterArguments(builder); break; } } private void appendSimpleAfterArguments(CodeBuilder builder) { builder.format("%1$s, %2$s, %3$s, %4$s", getTarget(), getArguments(), getReturnValue(), getException()); } private void appendStaticAfterArguments(CodeBuilder builder) { builder.format("%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, %6$s, %7$s", getTarget(), targetClass.getName(), targetMethod.getName(), getParameterTypes(), getArguments(), getReturnValue(), getException()); } private void appendApiIdAwareAfterArguments(CodeBuilder builder) { builder.format("%1$s, %2$d, %3$s, %4$s, %5$s", getTarget(), getApiId(), getArguments(), getReturnValue(), getException()); } private void appendCustomAfterArguments(CodeBuilder builder) { final Method interceptorMethod = interceptorDefinition.getAfterMethod(); final Class<?>[] interceptorParamTypes = interceptorMethod.getParameterTypes(); if (interceptorParamTypes.length == 0) { return; } builder.append(getTarget()); final int parameterSize = parameterBind(builder, interceptorParamTypes); final int bindSize = parameterSize + THIS_RETURN_EXCEPTION_SIZE; if (bindSize != interceptorParamTypes.length) { throw new IllegalStateException("interceptor arguments not matched. interceptorSize:" + interceptorParamTypes.length + " bindSize:" + bindSize); } // if (interceptorParamTypes.length >= 2) { builder.append(", "); builder.append(getReturnValue()); // } // if (interceptorParamTypes.length >= 3) { builder.append(", "); builder.append(getException()); // } } private int parameterBind(CodeBuilder builder, Class<?>[] interceptorParamTypes) { final int methodArgNum = targetMethod.getParameterTypes().length; final int interceptorArgNum = interceptorParamTypes.length - THIS_RETURN_EXCEPTION_SIZE; final int matchNum = Math.min(methodArgNum, interceptorArgNum); int parameterIndex = 0; for (; parameterIndex < matchNum; parameterIndex++) { builder.append(", ($w)$" + (parameterIndex + 1)); } for (; parameterIndex < interceptorArgNum; parameterIndex++) { builder.append(", null"); } return parameterIndex; } }