/** * Copyright 2014 SAP AG * * 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 org.aim.mainagent.scope; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.aim.api.exceptions.InstrumentationException; import org.aim.api.instrumentation.AbstractCustomScopeExtension; import org.aim.api.instrumentation.AbstractEnclosingProbe; import org.aim.api.instrumentation.AbstractEnclosingProbeExtension; import org.aim.api.instrumentation.AbstractInstAPIScope; import org.aim.api.instrumentation.AbstractInstApiScopeExtension; import org.aim.api.instrumentation.IScopeAnalyzer; import org.aim.api.instrumentation.description.internal.FlatInstrumentationEntity; import org.aim.api.instrumentation.description.internal.FlatScopeEntity; import org.aim.description.InstrumentationDescription; import org.aim.description.InstrumentationEntity; import org.aim.description.restrictions.Restriction; import org.aim.description.scopes.APIScope; import org.aim.description.scopes.ConstructorScope; import org.aim.description.scopes.CustomScope; import org.aim.description.scopes.MethodScope; import org.aim.description.scopes.MethodsEnclosingScope; import org.aim.logging.AIMLogger; import org.aim.logging.AIMLoggerFactory; import org.lpe.common.extension.ExtensionRegistry; import org.lpe.common.extension.IExtension; /** * Analyzes the whole scope. * * @author Alexander Wert * */ public class ScopeAnalysisController { private static final AIMLogger LOGGER = AIMLoggerFactory.getLogger(ScopeAnalysisController.class); private InstrumentationDescription instrumentationDescription; /** * Constructor. * * @param instDescription * instrumentation description */ public ScopeAnalysisController(InstrumentationDescription instDescription) { instrumentationDescription = instDescription; } /** * Creates flat internal instrumentation description. * * @param allLoadedClasses * all classes loaded in the JVM * @return set of flat instrumentation entities * @throws InstrumentationException * if scope cannot be resolved */ @SuppressWarnings({ "rawtypes" }) public Set<FlatInstrumentationEntity> resolveScopes(List<Class> allLoadedClasses) throws InstrumentationException { List<Class> filteredClasses = removeGlobalyExcludedClasses(allLoadedClasses); Map<IScopeAnalyzer, Set<String>> scopeAnalyzersToProbesMap = createScopeAnalyzerToProbesMapping(allLoadedClasses); Set<FlatInstrumentationEntity> instrumentationEntities = new HashSet<>(); Map<String, Class<? extends AbstractEnclosingProbe>> probeClasses = new HashMap<>(); for (Entry<IScopeAnalyzer, Set<String>> mapEntry : scopeAnalyzersToProbesMap.entrySet()) { IScopeAnalyzer sAnalyzer = mapEntry.getKey(); Set<String> probes = mapEntry.getValue(); Set<FlatScopeEntity> scopeEntities = new HashSet<>(); for (Class<?> clazz : filteredClasses) { try { sAnalyzer.visitClass(clazz, scopeEntities); } catch (Throwable t) { LOGGER.warn("failed to instrument class {}. Ignoring and resuming instrumentation.", clazz.getName()); } } for (FlatScopeEntity fse : scopeEntities) { for (String probe : probes) { Class<? extends AbstractEnclosingProbe> probeClass = null; if (!probeClasses.containsKey(probe)) { IExtension<?> ext = ExtensionRegistry.getSingleton().getExtension(probe); if (ext == null) { throw new InstrumentationException("Failed loading Probe class " + probe); } AbstractEnclosingProbeExtension probeExtension = (AbstractEnclosingProbeExtension) ext; probeClass = probeExtension.getProbeClass(); probeClasses.put(probe, probeClass); } else { probeClass = probeClasses.get(probe); } FlatInstrumentationEntity fiEntity = new FlatInstrumentationEntity(fse, probeClass); fiEntity.setScopeId(sAnalyzer.getScopeId()); instrumentationEntities.add(fiEntity); } } } return instrumentationEntities; } @SuppressWarnings("rawtypes") private List<Class> removeGlobalyExcludedClasses(List<Class> allLoadedClasses) { List<Class> toKeep = new ArrayList<>(); for (Class clazz : allLoadedClasses) { boolean invalidClass = false; try { String className = clazz.getName(); if (instrumentationDescription.getGlobalRestriction().isExcluded(className)) { // TODO: // use // IDM invalidClass = true; } else if (clazz.getClassLoader() == null) { invalidClass = true; } else if (clazz.isInterface() || clazz.isPrimitive() || clazz.isArray() || clazz.isAnnotation() || clazz.isAnonymousClass() || clazz.isEnum() || clazz.isSynthetic() || clazz.isLocalClass()) { invalidClass = true; } else { try { clazz.getClassLoader().loadClass(this.getClass().getName()); } catch (ClassNotFoundException cnfe) { invalidClass = true; } } } catch (Throwable t) { invalidClass = true; } if (!invalidClass) { toKeep.add(clazz); } } return toKeep; } @SuppressWarnings("rawtypes") private Map<IScopeAnalyzer, Set<String>> createScopeAnalyzerToProbesMapping(List<Class> allLoadedClasses) throws InstrumentationException { Map<IScopeAnalyzer, Set<String>> mapping = new HashMap<>(); for (InstrumentationEntity<MethodsEnclosingScope> mScopeEntity : instrumentationDescription .getInstrumentationEntities(MethodsEnclosingScope.class)) { IScopeAnalyzer scopeAnalyzer = null; if (mScopeEntity.getScope() instanceof MethodScope) { scopeAnalyzer = new MethodScopeAnalyzer(((MethodScope) mScopeEntity.getScope()).getMethods()); } else if (mScopeEntity.getScope() instanceof ConstructorScope) { scopeAnalyzer = new ConstructorScopeAnalyzer( ((ConstructorScope) mScopeEntity.getScope()).getTargetClasses()); } else if (mScopeEntity.getScope() instanceof CustomScope) { String scopeName = ((CustomScope) mScopeEntity.getScope()).getScopeName(); scopeAnalyzer = ExtensionRegistry.getSingleton().getExtensionArtifact( AbstractCustomScopeExtension.class, scopeName); if (scopeAnalyzer == null) { throw new InstrumentationException("Unable to instantiate scope analyzer for custom scope type " + scopeName); } } else if (mScopeEntity.getScope() instanceof APIScope) { String apiName = ((APIScope) mScopeEntity.getScope()).getApiName(); AbstractInstAPIScope apiScopeInstance = ExtensionRegistry.getSingleton().getExtensionArtifact( AbstractInstApiScopeExtension.class, apiName); if (apiScopeInstance == null) { throw new InstrumentationException("Unable to instantiate scope analyzer for API scope type " + apiName); } scopeAnalyzer = new APIScopeAnalyzer(apiScopeInstance, allLoadedClasses); } else { continue; } Restriction combinedRestriction = new Restriction(); combinedRestriction.getModifierIncludes().addAll(mScopeEntity.getLocalRestriction().getModifierIncludes()); combinedRestriction.getModifierIncludes().addAll( instrumentationDescription.getGlobalRestriction().getModifierIncludes()); combinedRestriction.getModifierExcludes().addAll(mScopeEntity.getLocalRestriction().getModifierExcludes()); combinedRestriction.getModifierExcludes().addAll( instrumentationDescription.getGlobalRestriction().getModifierExcludes()); combinedRestriction.getPackageIncludes().addAll(mScopeEntity.getLocalRestriction().getPackageIncludes()); combinedRestriction.getPackageIncludes().addAll( instrumentationDescription.getGlobalRestriction().getPackageIncludes()); combinedRestriction.getPackageExcludes().addAll(mScopeEntity.getLocalRestriction().getPackageExcludes()); combinedRestriction.getPackageExcludes().addAll( instrumentationDescription.getGlobalRestriction().getPackageExcludes()); scopeAnalyzer.setRestriction(combinedRestriction); scopeAnalyzer.setScopeId(mScopeEntity.getScope().getId()); mapping.put(scopeAnalyzer, mScopeEntity.getProbesAsStrings()); } return mapping; } }