Commit | Line | Data |
---|---|---|
38e2a2e9 JCK |
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; | |
6eca054d GB |
26 | import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.TmfXmlPatternSegmentBuilder; |
27 | import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.segment.TmfXmlPatternSegment; | |
38e2a2e9 JCK |
28 | import org.eclipse.tracecompass.segmentstore.core.ISegment; |
29 | import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; | |
30 | import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; | |
38e2a2e9 JCK |
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 | } |