| 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2016 Ericsson |
| 3 | * |
| 4 | * All rights reserved. This program and the accompanying materials are |
| 5 | * made available under the terms of the Eclipse Public License v1.0 which |
| 6 | * accompanies this distribution, and is available at |
| 7 | * http://www.eclipse.org/legal/epl-v10.html |
| 8 | ******************************************************************************/ |
| 9 | package org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider; |
| 10 | |
| 11 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
| 12 | |
| 13 | import java.io.File; |
| 14 | import java.util.Comparator; |
| 15 | import java.util.List; |
| 16 | import java.util.concurrent.CountDownLatch; |
| 17 | import java.util.stream.Collectors; |
| 18 | |
| 19 | import org.eclipse.core.runtime.IPath; |
| 20 | import org.eclipse.core.runtime.IProgressMonitor; |
| 21 | import org.eclipse.core.runtime.IStatus; |
| 22 | import org.eclipse.jdt.annotation.NonNull; |
| 23 | import org.eclipse.jdt.annotation.Nullable; |
| 24 | import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener; |
| 25 | import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; |
| 26 | import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.TmfXmlPatternSegmentBuilder; |
| 27 | import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.segment.TmfXmlPatternSegment; |
| 28 | import org.eclipse.tracecompass.segmentstore.core.ISegment; |
| 29 | import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; |
| 30 | import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; |
| 31 | import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule; |
| 32 | import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException; |
| 33 | import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect; |
| 34 | import org.eclipse.tracecompass.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems; |
| 35 | import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; |
| 36 | import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; |
| 37 | |
| 38 | import com.google.common.collect.ImmutableList; |
| 39 | |
| 40 | /** |
| 41 | * Analysis module for pattern matching within traces. This module creates two |
| 42 | * sub-analyses : A state system analysis that will execute the pattern on the |
| 43 | * trace and a segment store analysis that will build a segment store with the |
| 44 | * segments generated by the state system analysis. |
| 45 | * |
| 46 | * @author Jean-Christian Kouame |
| 47 | */ |
| 48 | public class XmlPatternAnalysis extends TmfAbstractAnalysisModule implements ITmfAnalysisModuleWithStateSystems, ISegmentStoreProvider { |
| 49 | |
| 50 | /** |
| 51 | * Segment store supplementary file extension |
| 52 | */ |
| 53 | public static final @NonNull String SEGMENT_STORE_EXTENSION = ".dat"; //$NON-NLS-1$ |
| 54 | /** |
| 55 | * state system supplementary file extension |
| 56 | */ |
| 57 | private static final @NonNull String STATE_SYSTEM_EXTENSION = ".ht"; //$NON-NLS-1$ |
| 58 | private static final String SEGMENT_STORE_SUFFIX = " segment store"; //$NON-NLS-1$ |
| 59 | private static final String STATE_SYSTEM_SUFFIX = " state system"; //$NON-NLS-1$ |
| 60 | private final CountDownLatch fInitialized = new CountDownLatch(1); |
| 61 | private XmlPatternStateSystemModule fStateSystemModule; |
| 62 | private XmlPatternSegmentStoreModule fSegmentStoreModule; |
| 63 | private boolean fInitializationSucceeded; |
| 64 | |
| 65 | /** |
| 66 | * Constructor |
| 67 | */ |
| 68 | public XmlPatternAnalysis() { |
| 69 | super(); |
| 70 | fSegmentStoreModule = new XmlPatternSegmentStoreModule(this); |
| 71 | fStateSystemModule = new XmlPatternStateSystemModule(fSegmentStoreModule); |
| 72 | } |
| 73 | |
| 74 | @Override |
| 75 | public @Nullable ISegmentStore<@NonNull ISegment> getSegmentStore() { |
| 76 | return fSegmentStoreModule.getSegmentStore(); |
| 77 | } |
| 78 | |
| 79 | @Override |
| 80 | public @Nullable ITmfStateSystem getStateSystem(@NonNull String id) { |
| 81 | return fStateSystemModule.getStateSystem(id); |
| 82 | } |
| 83 | |
| 84 | @Override |
| 85 | public @NonNull Iterable<@NonNull ITmfStateSystem> getStateSystems() { |
| 86 | return fStateSystemModule.getStateSystems(); |
| 87 | } |
| 88 | |
| 89 | @Override |
| 90 | public boolean waitForInitialization() { |
| 91 | try { |
| 92 | fInitialized.await(); |
| 93 | } catch (InterruptedException e) { |
| 94 | return false; |
| 95 | } |
| 96 | return fInitializationSucceeded; |
| 97 | } |
| 98 | |
| 99 | @Override |
| 100 | protected boolean executeAnalysis(@NonNull IProgressMonitor monitor) throws TmfAnalysisException { |
| 101 | ITmfTrace trace = getTrace(); |
| 102 | if (trace == null) { |
| 103 | /* This analysis was cancelled in the meantime */ |
| 104 | analysisReady(false); |
| 105 | return false; |
| 106 | } |
| 107 | |
| 108 | File segmentStoreFile = getSupplementaryFile(getSegmentStoreFileName()); |
| 109 | File stateSystemFile = getSupplementaryFile(getStateSystemFileName()); |
| 110 | if (segmentStoreFile == null || stateSystemFile == null) { |
| 111 | analysisReady(false); |
| 112 | return false; |
| 113 | } |
| 114 | |
| 115 | if (!segmentStoreFile.exists()) { |
| 116 | fStateSystemModule.cancel(); |
| 117 | stateSystemFile.delete(); |
| 118 | } |
| 119 | |
| 120 | IStatus segmentStoreStatus = fSegmentStoreModule.schedule(); |
| 121 | IStatus stateSystemStatus = fStateSystemModule.schedule(); |
| 122 | if (!(segmentStoreStatus.isOK() && stateSystemStatus.isOK())) { |
| 123 | cancelSubAnalyses(); |
| 124 | analysisReady(false); |
| 125 | return false; |
| 126 | } |
| 127 | |
| 128 | /* Wait until the state system module is initialized */ |
| 129 | if (!fStateSystemModule.waitForInitialization()) { |
| 130 | analysisReady(false); |
| 131 | cancelSubAnalyses(); |
| 132 | return false; |
| 133 | } |
| 134 | |
| 135 | ITmfStateSystem stateSystem = fStateSystemModule.getStateSystem(); |
| 136 | if (stateSystem == null) { |
| 137 | analysisReady(false); |
| 138 | throw new IllegalStateException("Initialization of the state system module succeeded but the statesystem is null"); //$NON-NLS-1$ |
| 139 | } |
| 140 | |
| 141 | analysisReady(true); |
| 142 | |
| 143 | return fStateSystemModule.waitForCompletion(monitor) && fSegmentStoreModule.waitForCompletion(monitor); |
| 144 | } |
| 145 | |
| 146 | @Override |
| 147 | protected void canceling() { |
| 148 | cancelSubAnalyses(); |
| 149 | } |
| 150 | |
| 151 | private void cancelSubAnalyses() { |
| 152 | fStateSystemModule.cancel(); |
| 153 | fSegmentStoreModule.cancel(); |
| 154 | } |
| 155 | |
| 156 | @Override |
| 157 | public void dispose() { |
| 158 | /* |
| 159 | * The sub-analyses are not registered to the trace directly, so we need |
| 160 | * to tell them when the trace is disposed. |
| 161 | */ |
| 162 | super.dispose(); |
| 163 | fStateSystemModule.dispose(); |
| 164 | fSegmentStoreModule.dispose(); |
| 165 | } |
| 166 | |
| 167 | @Override |
| 168 | public void setId(@NonNull String id) { |
| 169 | super.setId(id); |
| 170 | fStateSystemModule.setId(id); |
| 171 | fSegmentStoreModule.setId(id); |
| 172 | } |
| 173 | |
| 174 | @Override |
| 175 | public void setName(@NonNull String name) { |
| 176 | super.setName(name); |
| 177 | fStateSystemModule.setName(name + STATE_SYSTEM_SUFFIX); |
| 178 | fSegmentStoreModule.setName(name + SEGMENT_STORE_SUFFIX); |
| 179 | } |
| 180 | |
| 181 | @Override |
| 182 | public boolean setTrace(ITmfTrace trace) throws TmfAnalysisException { |
| 183 | if (!super.setTrace(trace)) { |
| 184 | return false; |
| 185 | } |
| 186 | |
| 187 | /* |
| 188 | * Since these sub-analyzes are not built from an extension point, we |
| 189 | * have to assign the trace ourselves. Very important to do so before |
| 190 | * calling schedule()! |
| 191 | */ |
| 192 | return fSegmentStoreModule.setTrace(trace) && fStateSystemModule.setTrace(trace); |
| 193 | } |
| 194 | |
| 195 | /** |
| 196 | * Sets the file path of the XML file and the id of pattern analysis in the |
| 197 | * file |
| 198 | * |
| 199 | * @param file |
| 200 | * The full path to the XML file |
| 201 | */ |
| 202 | public void setXmlFile(IPath file) { |
| 203 | fStateSystemModule.setXmlFile(file); |
| 204 | } |
| 205 | |
| 206 | /** |
| 207 | * Make the module available and set whether the initialization succeeded or |
| 208 | * not. If not, no state system is available and |
| 209 | * {@link #waitForInitialization()} should return false. |
| 210 | * |
| 211 | * @param success |
| 212 | * True if the initialization went well, false otherwise |
| 213 | */ |
| 214 | private void analysisReady(boolean succeeded) { |
| 215 | fInitializationSucceeded = succeeded; |
| 216 | fInitialized.countDown(); |
| 217 | } |
| 218 | |
| 219 | private @Nullable File getSupplementaryFile(String filename) { |
| 220 | ITmfTrace trace = getTrace(); |
| 221 | if (trace == null) { |
| 222 | return null; |
| 223 | } |
| 224 | String directory = TmfTraceManager.getSupplementaryFileDir(trace); |
| 225 | File file = new File(directory + filename); |
| 226 | return file; |
| 227 | } |
| 228 | |
| 229 | private String getStateSystemFileName() { |
| 230 | return fStateSystemModule.getId() + STATE_SYSTEM_EXTENSION; |
| 231 | } |
| 232 | |
| 233 | private String getSegmentStoreFileName() { |
| 234 | return fSegmentStoreModule.getId() + SEGMENT_STORE_EXTENSION; |
| 235 | } |
| 236 | |
| 237 | @Override |
| 238 | public void addListener(@NonNull IAnalysisProgressListener listener) { |
| 239 | fSegmentStoreModule.addListener(listener); |
| 240 | } |
| 241 | |
| 242 | @Override |
| 243 | public void removeListener(@NonNull IAnalysisProgressListener listener) { |
| 244 | fSegmentStoreModule.removeListener(listener); |
| 245 | } |
| 246 | |
| 247 | @Override |
| 248 | public Iterable<ISegmentAspect> getSegmentAspects() { |
| 249 | return ImmutableList.of(PatternSegmentNameAspect.INSTANCE, PatternSegmentContentAspect.INSTANCE); |
| 250 | } |
| 251 | |
| 252 | private static class PatternSegmentNameAspect implements ISegmentAspect { |
| 253 | public static final @NonNull ISegmentAspect INSTANCE = new PatternSegmentNameAspect(); |
| 254 | |
| 255 | private PatternSegmentNameAspect() {} |
| 256 | |
| 257 | @Override |
| 258 | public String getHelpText() { |
| 259 | return checkNotNull(Messages.PatternSegmentNameAspect_HelpText); |
| 260 | } |
| 261 | @Override |
| 262 | public String getName() { |
| 263 | return checkNotNull(Messages.PatternSegmentNameAspect_Name); |
| 264 | } |
| 265 | @Override |
| 266 | public @Nullable Comparator<?> getComparator() { |
| 267 | return null; |
| 268 | } |
| 269 | @Override |
| 270 | public @Nullable String resolve(ISegment segment) { |
| 271 | if (segment instanceof TmfXmlPatternSegment) { |
| 272 | return ((TmfXmlPatternSegment) segment).getName() |
| 273 | .substring(TmfXmlPatternSegmentBuilder.PATTERN_SEGMENT_NAME_PREFIX.length()); |
| 274 | } |
| 275 | return EMPTY_STRING; |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | private static class PatternSegmentContentAspect implements ISegmentAspect { |
| 280 | public static final @NonNull ISegmentAspect INSTANCE = new PatternSegmentContentAspect(); |
| 281 | |
| 282 | private PatternSegmentContentAspect() {} |
| 283 | |
| 284 | @Override |
| 285 | public String getHelpText() { |
| 286 | return checkNotNull(Messages.PatternSegmentContentAspect_HelpText); |
| 287 | } |
| 288 | @Override |
| 289 | public String getName() { |
| 290 | return checkNotNull(Messages.PatternSegmentContentAspect_Content); |
| 291 | } |
| 292 | @Override |
| 293 | public @Nullable Comparator<?> getComparator() { |
| 294 | return null; |
| 295 | } |
| 296 | @Override |
| 297 | public @Nullable String resolve(ISegment segment) { |
| 298 | if (segment instanceof TmfXmlPatternSegment) { |
| 299 | List<String> values = ((TmfXmlPatternSegment) segment).getContent().entrySet().stream().map(c -> c.getKey() + '=' + c.getValue()).collect(Collectors.toList()); |
| 300 | return String.join(", ", values); //$NON-NLS-1$ |
| 301 | } |
| 302 | return EMPTY_STRING; |
| 303 | } |
| 304 | } |
| 305 | } |