/******************************************************************************* * Copyright (c) 2015, 2016 Ericsson * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.eclipse.tracecompass.analysis.timing.core.segmentstore; import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ListenerList; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.common.core.NonNullUtils; import org.eclipse.tracecompass.segmentstore.core.ISegment; import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; import org.eclipse.tracecompass.segmentstore.core.SegmentStoreFactory; 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.trace.ITmfTrace; import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; /** * Abstract analysis module to generate a segment store. It is a base class that * can be used as a shortcut by analysis who just need to build a single segment * store. * * @author Bernd Hufmann * @since 2.0 * */ public abstract class AbstractSegmentStoreAnalysisModule extends TmfAbstractAnalysisModule implements ISegmentStoreProvider { private final ListenerList fListeners = new ListenerList(ListenerList.IDENTITY); private @Nullable ISegmentStore<ISegment> fSegmentStore; @Override public void addListener(IAnalysisProgressListener listener) { fListeners.add(listener); } @Override public void removeListener(IAnalysisProgressListener listener) { fListeners.remove(listener); } /** * Returns all the listeners * * @return latency listeners */ protected Iterable<IAnalysisProgressListener> getListeners() { List<IAnalysisProgressListener> listeners = new ArrayList<>(); for (Object listener : fListeners.getListeners()) { if (listener != null) { listeners.add((IAnalysisProgressListener) listener); } } return listeners; } @Override public Iterable<ISegmentAspect> getSegmentAspects() { return Collections.emptyList(); } /** * Returns the file name for storing segment store * * @return segment store fine name, or null if you don't want a file */ protected @Nullable String getDataFileName() { return null; } /** * Read an object from the ObjectInputStream. * * @param ois * the ObjectInputStream to used * @return the read object * @throws ClassNotFoundException * - Class of a serialized object cannot be found. * @throws IOException * - Any of the usual Input/Output related exceptions. */ protected abstract Object[] readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException; /** * Fills the segment store. This is the main method that children classes * need to implement to build the segment store. For example, if the * segments are found by parsing the events of a trace, the event request * would be done in this method. * * Note: After this method, the segment store should be completed, so it * should also close the segment store at the end of the analysis * * @param segmentStore * The segment store to fill * @param monitor * Progress monitor * @return Whether the segments was resolved successfully or not * @throws TmfAnalysisException * Method may throw an analysis exception */ protected abstract boolean buildAnalysisSegments(ISegmentStore<ISegment> segmentStore, IProgressMonitor monitor) throws TmfAnalysisException; @Override public @Nullable ISegmentStore<ISegment> getSegmentStore() { return fSegmentStore; } @Override public void dispose() { super.dispose(); ISegmentStore<ISegment> store = fSegmentStore; if (store != null) { store.dispose(); } } @Override protected boolean executeAnalysis(IProgressMonitor monitor) throws TmfAnalysisException { ITmfTrace trace = checkNotNull(getTrace()); final @Nullable String dataFileName = getDataFileName(); if (dataFileName != null) { /* See if the data file already exists on disk */ String dir = TmfTraceManager.getSupplementaryFileDir(trace); final Path file = Paths.get(dir, dataFileName); if (Files.exists(file)) { /* Attempt to read the existing file */ try (ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(file))) { Object[] segmentArray = readObject(ois); ISegmentStore<ISegment> store = SegmentStoreFactory.createSegmentStore(NonNullUtils.checkNotNullContents(segmentArray)); fSegmentStore = store; sendUpdate(store); return true; } catch (IOException | ClassNotFoundException | ClassCastException e) { /* * We did not manage to read the file successfully, we will * just fall-through to rebuild a new one. */ try { Files.delete(file); } catch (IOException e1) { } } } } ISegmentStore<ISegment> segmentStore = SegmentStoreFactory.createSegmentStore(); boolean completed = buildAnalysisSegments(segmentStore, monitor); if (!completed) { return false; } fSegmentStore = segmentStore; if (dataFileName != null) { String dir = TmfTraceManager.getSupplementaryFileDir(trace); final Path file = Paths.get(dir, dataFileName); /* Serialize the collections to disk for future usage */ try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(file))) { oos.writeObject(segmentStore.toArray()); } catch (IOException e) { /* * Didn't work, oh well. We will just re-read the trace next * time */ } } sendUpdate(segmentStore); return true; } /** * Send the segment store to all its listener * * @param store * The segment store to broadcast */ protected void sendUpdate(final ISegmentStore<ISegment> store) { for (IAnalysisProgressListener listener : getListeners()) { listener.onComplete(this, store); } } }