| /******************************************************************************* |
| * Copyright (c) 2016 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| ******************************************************************************/ |
| package org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider; |
| |
| import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.file.Files; |
| import java.util.Comparator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Objects; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.stream.Collectors; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener; |
| import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; |
| import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator; |
| import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.fsm.compile.TmfXmlPatternCu; |
| import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.segment.TmfXmlPatternSegment; |
| import org.eclipse.tracecompass.segmentstore.core.ISegment; |
| import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; |
| import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; |
| import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule; |
| import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; |
| import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect; |
| import org.eclipse.tracecompass.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems; |
| import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; |
| import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; |
| |
| import com.google.common.collect.ImmutableList; |
| |
| /** |
| * Analysis module for pattern matching within traces. This module creates two |
| * sub-analyses : A state system analysis that will execute the pattern on the |
| * trace and a segment store analysis that will build a segment store with the |
| * segments generated by the state system analysis. |
| * |
| * @author Jean-Christian Kouame |
| */ |
| public class XmlPatternAnalysis extends TmfAbstractAnalysisModule implements ITmfAnalysisModuleWithStateSystems, ISegmentStoreProvider { |
| |
| /** |
| * Segment store supplementary file extension |
| */ |
| public static final @NonNull String SEGMENT_STORE_EXTENSION = ".dat"; //$NON-NLS-1$ |
| /** |
| * state system supplementary file extension |
| */ |
| private static final @NonNull String STATE_SYSTEM_EXTENSION = ".ht"; //$NON-NLS-1$ |
| private static final String SEGMENT_STORE_SUFFIX = " segment store"; //$NON-NLS-1$ |
| private static final String STATE_SYSTEM_SUFFIX = " state system"; //$NON-NLS-1$ |
| private final CountDownLatch fInitialized = new CountDownLatch(1); |
| private final XmlPatternStateSystemModule fStateSystemModule; |
| private final XmlPatternSegmentStoreModule fSegmentStoreModule; |
| private boolean fInitializationSucceeded; |
| private String fViewLabelPrefix; |
| |
| /** |
| * Constructor |
| * |
| * @param patternCu |
| * The pattern compilation unit |
| * @param analysisid |
| * The analysis ID |
| */ |
| public XmlPatternAnalysis(@NonNull String analysisid, TmfXmlPatternCu patternCu) { |
| super(); |
| fSegmentStoreModule = new XmlPatternSegmentStoreModule(this); |
| fStateSystemModule = new XmlPatternStateSystemModule(fSegmentStoreModule, patternCu); |
| setId(analysisid); |
| } |
| |
| @Override |
| public Map<@NonNull String, @NonNull Integer> getProviderVersions() { |
| return fStateSystemModule.getProviderVersions(); |
| } |
| |
| @Override |
| public @Nullable ISegmentStore<@NonNull ISegment> getSegmentStore() { |
| return fSegmentStoreModule.getSegmentStore(); |
| } |
| |
| @Override |
| public @Nullable ITmfStateSystem getStateSystem(@NonNull String id) { |
| return fStateSystemModule.getStateSystem(id); |
| } |
| |
| @Override |
| public @NonNull Iterable<@NonNull ITmfStateSystem> getStateSystems() { |
| return fStateSystemModule.getStateSystems(); |
| } |
| |
| /** |
| * Set the associated view label prefix |
| * |
| * @param viewLabelPrefix |
| * The view label prefix |
| */ |
| public void setViewLabelPrefix(String viewLabelPrefix) { |
| fViewLabelPrefix = viewLabelPrefix; |
| } |
| |
| /** |
| * Get the associated view label prefix |
| * |
| * @return The view label prefix |
| */ |
| public String getViewLabelPrefix() { |
| return fViewLabelPrefix; |
| } |
| |
| @Override |
| public boolean waitForInitialization() { |
| try { |
| fInitialized.await(); |
| } catch (InterruptedException e) { |
| Thread.currentThread().interrupt(); |
| return false; |
| } |
| return fInitializationSucceeded; |
| } |
| |
| @Override |
| protected boolean executeAnalysis(@NonNull IProgressMonitor monitor) throws TmfAnalysisException { |
| ITmfTrace trace = getTrace(); |
| if (trace == null) { |
| /* This analysis was cancelled in the meantime */ |
| analysisReady(false); |
| return false; |
| } |
| |
| File segmentStoreFile = getSupplementaryFile(getSegmentStoreFileName()); |
| File stateSystemFile = getSupplementaryFile(getStateSystemFileName()); |
| if (segmentStoreFile == null || stateSystemFile == null) { |
| analysisReady(false); |
| return false; |
| } |
| |
| if (!segmentStoreFile.exists()) { |
| fStateSystemModule.cancel(); |
| if (stateSystemFile.exists()) { |
| try { |
| Files.delete(stateSystemFile.toPath()); |
| } catch (IOException e) { |
| // log it, failing to delete doesn't garantee failure |
| Activator.logWarning(e.getMessage(), e); |
| } |
| } |
| } |
| |
| IStatus segmentStoreStatus = fSegmentStoreModule.schedule(); |
| IStatus stateSystemStatus = fStateSystemModule.schedule(); |
| if (!(segmentStoreStatus.isOK() && stateSystemStatus.isOK())) { |
| cancelSubAnalyses(); |
| analysisReady(false); |
| return false; |
| } |
| |
| /* Wait until the state system module is initialized */ |
| if (!fStateSystemModule.waitForInitialization()) { |
| analysisReady(false); |
| cancelSubAnalyses(); |
| return false; |
| } |
| |
| ITmfStateSystem stateSystem = fStateSystemModule.getStateSystem(); |
| if (stateSystem == null) { |
| analysisReady(false); |
| throw new IllegalStateException("Initialization of the state system module succeeded but the statesystem is null"); //$NON-NLS-1$ |
| } |
| |
| analysisReady(true); |
| |
| return fStateSystemModule.waitForCompletion(monitor) && fSegmentStoreModule.waitForCompletion(monitor); |
| } |
| |
| @Override |
| protected void canceling() { |
| cancelSubAnalyses(); |
| } |
| |
| private void cancelSubAnalyses() { |
| fStateSystemModule.cancel(); |
| fSegmentStoreModule.cancel(); |
| } |
| |
| @Override |
| public void dispose() { |
| /* |
| * The sub-analyses are not registered to the trace directly, so we need |
| * to tell them when the trace is disposed. |
| */ |
| super.dispose(); |
| fStateSystemModule.dispose(); |
| fSegmentStoreModule.dispose(); |
| } |
| |
| @Override |
| public void setId(@NonNull String id) { |
| super.setId(id); |
| fStateSystemModule.setId(id); |
| fSegmentStoreModule.setId(id); |
| } |
| |
| @Override |
| public void setName(@NonNull String name) { |
| super.setName(name); |
| fStateSystemModule.setName(name + STATE_SYSTEM_SUFFIX); |
| fSegmentStoreModule.setName(name + SEGMENT_STORE_SUFFIX); |
| } |
| |
| @Override |
| public boolean setTrace(ITmfTrace trace) throws TmfAnalysisException { |
| if (!super.setTrace(trace)) { |
| return false; |
| } |
| |
| /* |
| * Since these sub-analyzes are not built from an extension point, we |
| * have to assign the trace ourselves. Very important to do so before |
| * calling schedule()! |
| */ |
| return fSegmentStoreModule.setTrace(trace) && fStateSystemModule.setTrace(trace); |
| } |
| |
| /** |
| * Make the module available and set whether the initialization succeeded or |
| * not. If not, no state system is available and |
| * {@link #waitForInitialization()} should return false. |
| * |
| * @param success |
| * True if the initialization went well, false otherwise |
| */ |
| private void analysisReady(boolean succeeded) { |
| fInitializationSucceeded = succeeded; |
| fInitialized.countDown(); |
| } |
| |
| private @Nullable File getSupplementaryFile(String filename) { |
| ITmfTrace trace = getTrace(); |
| if (trace == null) { |
| return null; |
| } |
| String directory = TmfTraceManager.getSupplementaryFileDir(trace); |
| return new File(directory + filename); |
| } |
| |
| private String getStateSystemFileName() { |
| return fStateSystemModule.getId() + STATE_SYSTEM_EXTENSION; |
| } |
| |
| private String getSegmentStoreFileName() { |
| return fSegmentStoreModule.getId() + SEGMENT_STORE_EXTENSION; |
| } |
| |
| @Override |
| public void addListener(@NonNull IAnalysisProgressListener listener) { |
| fSegmentStoreModule.addListener(listener); |
| } |
| |
| @Override |
| public void removeListener(@NonNull IAnalysisProgressListener listener) { |
| fSegmentStoreModule.removeListener(listener); |
| } |
| |
| @Override |
| public Iterable<ISegmentAspect> getSegmentAspects() { |
| return ImmutableList.of(PatternSegmentNameAspect.INSTANCE, PatternSegmentContentAspect.INSTANCE); |
| } |
| |
| private static class PatternSegmentNameAspect implements ISegmentAspect { |
| public static final @NonNull ISegmentAspect INSTANCE = new PatternSegmentNameAspect(); |
| |
| private PatternSegmentNameAspect() {} |
| |
| @Override |
| public String getHelpText() { |
| return checkNotNull(Messages.PatternSegmentNameAspect_HelpText); |
| } |
| @Override |
| public String getName() { |
| return checkNotNull(Messages.PatternSegmentNameAspect_Name); |
| } |
| @Override |
| public @Nullable Comparator<?> getComparator() { |
| return null; |
| } |
| @Override |
| public @Nullable String resolve(ISegment segment) { |
| if (segment instanceof TmfXmlPatternSegment) { |
| return ((TmfXmlPatternSegment) segment).getName(); |
| } |
| return EMPTY_STRING; |
| } |
| } |
| |
| private static class PatternSegmentContentAspect implements ISegmentAspect { |
| public static final @NonNull ISegmentAspect INSTANCE = new PatternSegmentContentAspect(); |
| |
| private PatternSegmentContentAspect() {} |
| |
| @Override |
| public String getHelpText() { |
| return checkNotNull(Messages.PatternSegmentContentAspect_HelpText); |
| } |
| @Override |
| public String getName() { |
| return checkNotNull(Messages.PatternSegmentContentAspect_Content); |
| } |
| @Override |
| public @Nullable Comparator<?> getComparator() { |
| return null; |
| } |
| @Override |
| public @Nullable String resolve(ISegment segment) { |
| if (segment instanceof TmfXmlPatternSegment) { |
| return ((TmfXmlPatternSegment) segment).getContent().entrySet().stream().map(c -> c.getKey() + '=' + c.getValue()).collect(Collectors.joining(", ")); //$NON-NLS-1$ |
| } |
| return EMPTY_STRING; |
| } |
| } |
| |
| @Override |
| public boolean waitForCompletion() { |
| return super.waitForCompletion() |
| && fStateSystemModule.waitForCompletion() |
| && fSegmentStoreModule.waitForCompletion(); |
| } |
| |
| @Override |
| public boolean waitForCompletion(@NonNull IProgressMonitor monitor) { |
| return super.waitForCompletion(monitor) |
| && fStateSystemModule.waitForCompletion(monitor) |
| && fSegmentStoreModule.waitForCompletion(monitor); |
| } |
| |
| // ------------------------------------------------------------------------ |
| // ITmfPropertiesProvider |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * @since 2.0 |
| */ |
| @Override |
| public @NonNull Map<@NonNull String, @NonNull String> getProperties() { |
| Map<@NonNull String, @NonNull String> properties = super.getProperties(); |
| |
| // Add the sub-modules' properties |
| TmfAbstractAnalysisModule module = fStateSystemModule; |
| if (module != null) { |
| for (Entry<String, String> entry : module.getProperties().entrySet()) { |
| String value = entry.getValue(); |
| if (value != null) { |
| properties.put(Objects.requireNonNull(Messages.PatternAnalysis_StateSystemPrefix + ' ' + entry.getKey()), value); |
| } |
| } |
| } |
| module = fSegmentStoreModule; |
| if (module != null) { |
| for (Entry<String, String> entry : module.getProperties().entrySet()) { |
| String value = entry.getValue(); |
| if (value != null) { |
| properties.put(Objects.requireNonNull(Messages.PatternAnalysis_SegmentStorePrefix + ' ' + entry.getKey()), value); |
| } |
| } |
| } |
| return properties; |
| } |
| |
| } |