/**
* 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;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.aim.api.events.AbstractEventProbeExtension;
import org.aim.api.exceptions.InstrumentationException;
import org.aim.api.exceptions.MeasurementException;
import org.aim.api.instrumentation.AbstractCustomScopeExtension;
import org.aim.api.instrumentation.AbstractEnclosingProbeExtension;
import org.aim.api.instrumentation.AbstractInstApiScopeExtension;
import org.aim.api.instrumentation.InstrumentationUtilsController;
import org.aim.api.instrumentation.description.internal.FlatInstrumentationEntity;
import org.aim.api.instrumentation.description.internal.InstrumentationConstants;
import org.aim.api.instrumentation.entities.FlatInstrumentationState;
import org.aim.api.instrumentation.entities.SupportedExtensions;
import org.aim.api.measurement.sampling.AbstractSamplerExtension;
import org.aim.description.InstrumentationDescription;
import org.aim.description.scopes.AllocationScope;
import org.aim.description.scopes.ConstructorScope;
import org.aim.description.scopes.MemoryScope;
import org.aim.description.scopes.MethodScope;
import org.aim.description.scopes.SynchronizedScope;
import org.aim.description.scopes.TraceScope;
import org.aim.mainagent.probes.IncrementalProbeExtension;
import org.aim.mainagent.sampling.Sampling;
import org.lpe.common.extension.ExtensionRegistry;
import org.lpe.common.extension.IExtension;
/**
* Coordinates the instrumentation process.
*
* @author Alexander Wert
*
*/
public final class AdaptiveInstrumentationFacade {
private static AdaptiveInstrumentationFacade instance;
/**
* Singleton instance.
*
* @return singleton instance
*/
public static synchronized AdaptiveInstrumentationFacade getInstance() {
if (instance == null) {
instance = new AdaptiveInstrumentationFacade();
}
return instance;
}
private MethodInstrumentor methodInstrumentor;
private TraceInstrumentor traceInstrumentor;
private EventInstrumentor eventInstrumentor;
private SupportedExtensions extensions = null;
private AdaptiveInstrumentationFacade() {
methodInstrumentor = new MethodInstrumentor();
traceInstrumentor = TraceInstrumentor.getInstance();
eventInstrumentor = EventInstrumentor.getInstance();
}
/**
* Instruments the target application according to the passed
* instrumentation. Note, instrumentation is additive, thus, calling this
* method several times with different instrumentation descriptions results
* in a joined instrumentation.
*
* @param instrumentationDescription
* describes the instrumentation to be made
* @throws InstrumentationException
* if instrumentation fails
*/
public synchronized void instrument(InstrumentationDescription instrumentationDescription)
throws InstrumentationException {
instrumentationDescription.getGlobalRestriction().addPackageExclude(InstrumentationConstants.AIM_PACKAGE);
instrumentationDescription.getGlobalRestriction().addPackageExclude(InstrumentationConstants.JAVA_PACKAGE);
instrumentationDescription.getGlobalRestriction().addPackageExclude(InstrumentationConstants.JAVASSIST_PACKAGE);
instrumentationDescription.getGlobalRestriction().addPackageExclude(InstrumentationConstants.JAVAX_PACKAGE);
instrumentationDescription.getGlobalRestriction()
.addPackageExclude(InstrumentationConstants.LPE_COMMON_PACKAGE);
methodInstrumentor.instrument(instrumentationDescription);
traceInstrumentor.instrument(instrumentationDescription);
eventInstrumentor.instrument(instrumentationDescription);
// TODO: add Statement Instrumentation
if (!instrumentationDescription.getSamplingDescriptions().isEmpty()) {
try {
Sampling.getInstance().addMonitoringJob(instrumentationDescription.getSamplingDescriptions());
} catch (MeasurementException e) {
throw new InstrumentationException(e);
}
}
}
/**
* Reverts all instrumentation steps.
*
* @throws InstrumentationException
* if instrumentation fails
*/
public synchronized void undoInstrumentation() throws InstrumentationException {
methodInstrumentor.undoInstrumentation();
traceInstrumentor.undoInstrumentation();
eventInstrumentor.undoInstrumentation();
Sampling.getInstance().clearMonitoringJobs();
InstrumentationUtilsController.getInstance().clear();
}
/**
* Retrieves the flat instrumentation state.
*
* @return flat instrumentation state
*/
public synchronized FlatInstrumentationState getInstrumentationState() {
FlatInstrumentationState fmInstrumentation = new FlatInstrumentationState();
for (FlatInstrumentationEntity fie : methodInstrumentor.getCurrentInstrumentationState()) {
fmInstrumentation.addEntity(fie.getMethodSignature(), fie.getProbeType().getName());
}
return fmInstrumentation;
}
/**
* retrieve supported extensions.
*
* @return Object wrapping all extensions supported by this agent.
* @throws InstrumentationException
* thrown if extensions cannot be retrieved
*/
public synchronized SupportedExtensions getSupportedExtensions() throws InstrumentationException {
if (extensions == null) {
extensions = new SupportedExtensions();
Set<Class<?>> knownConcreteScopeClasses = new HashSet<>();
knownConcreteScopeClasses.add(AllocationScope.class);
knownConcreteScopeClasses.add(ConstructorScope.class);
knownConcreteScopeClasses.add(MemoryScope.class);
knownConcreteScopeClasses.add(MethodScope.class);
knownConcreteScopeClasses.add(SynchronizedScope.class);
knownConcreteScopeClasses.add(TraceScope.class);
Map<String, Set<Class<?>>> tempProbeScopeMapping = new HashMap<>();
for (IExtension<?> extension : ExtensionRegistry.getSingleton().getExtensions()) {
if (extension instanceof AbstractCustomScopeExtension) {
extensions.getCustomScopeExtensions().add(extension.getName());
knownConcreteScopeClasses.add(extension.createExtensionArtifact().getClass());
} else if (extension instanceof AbstractEnclosingProbeExtension) {
if (extension instanceof IncrementalProbeExtension) {
continue;
}
tempProbeScopeMapping.put(extension.getName(),
((AbstractEnclosingProbeExtension) extension).getScopeDependencies());
} else if (extension instanceof AbstractEventProbeExtension) {
tempProbeScopeMapping.put(extension.getName(),
((AbstractEventProbeExtension) extension).getScopeDependencies());
} else if (extension instanceof AbstractInstApiScopeExtension) {
extensions.getApiScopeExtensions().add(extension.getName());
knownConcreteScopeClasses.add(extension.createExtensionArtifact().getClass());
} else if (extension instanceof AbstractSamplerExtension) {
extensions.getSamplerExtensions().add(extension.getName());
}
}
for (String probeName : tempProbeScopeMapping.keySet()) {
Set<String> scopes = new HashSet<>();
for (Class<?> concreteScope : knownConcreteScopeClasses) {
supportedScopeLoop: for (Class<?> supportedScope : tempProbeScopeMapping.get(probeName)) {
if (supportedScope.isAssignableFrom(concreteScope)) {
scopes.add(concreteScope.getName());
break supportedScopeLoop;
}
}
}
extensions.addProbeExtension(probeName, scopes);
}
}
return extensions;
}
}