/*******************************************************************************
* Copyright (c) 2014, 2015 École Polytechnique de Montréal
*
* 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
*
* Contributors:
* Florian Wininger - Initial API and implementation
*******************************************************************************/
package org.eclipse.tracecompass.internal.tmf.analysis.xml.core.stateprovider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.ITmfXmlModelFactory;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.TmfXmlEventHandler;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.TmfXmlLocation;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.TmfXmlMapEntry;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.readwrite.TmfXmlReadWriteModelFactory;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* This is the state change input plug-in for TMF's state system which handles
* the XML Format
*
* @author Florian Wininger
*/
public class XmlStateProvider extends AbstractTmfStateProvider implements IXmlStateSystemContainer {
private final IPath fFilePath;
private final @NonNull String fStateId;
/** List of all Event Handlers */
private final List<TmfXmlEventHandler> fEventHandlers = new ArrayList<>();
/** List of all Locations */
private final @NonNull Set<@NonNull TmfXmlLocation> fLocations;
/** Map for defined values */
private final Map<String, String> fDefinedValues = new HashMap<>();
private final @NonNull Map<@NonNull String, @NonNull Set<@NonNull TmfXmlMapEntry>> fMappingGroups;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
/**
* Instantiate a new state provider plug-in.
*
* @param trace
* The trace
* @param stateid
* The state system id, corresponding to the analysis_id
* attribute of the state provider element of the XML file
* @param file
* Path to the XML file containing the state provider definition
*/
public XmlStateProvider(@NonNull ITmfTrace trace, @NonNull String stateid, IPath file) {
super(trace, stateid);
fStateId = stateid;
fFilePath = file;
Element doc = XmlUtils.getElementInFile(fFilePath.makeAbsolute().toOSString(), TmfXmlStrings.STATE_PROVIDER, fStateId);
if (doc == null) {
fLocations = new HashSet<>();
fMappingGroups = new HashMap<>();
return;
}
ITmfXmlModelFactory modelFactory = TmfXmlReadWriteModelFactory.getInstance();
/* parser for defined Values */
NodeList definedStateNodes = doc.getElementsByTagName(TmfXmlStrings.DEFINED_VALUE);
for (int i = 0; i < definedStateNodes.getLength(); i++) {
Element element = (Element) definedStateNodes.item(i);
fDefinedValues.put(element.getAttribute(TmfXmlStrings.NAME), element.getAttribute(TmfXmlStrings.VALUE));
}
/* parser for the locations */
List<Element> childElements = XmlUtils.getChildElements(doc, TmfXmlStrings.LOCATION);
Set<@NonNull TmfXmlLocation> locations = new HashSet<>();
for (Element element : childElements) {
if (element == null) {
continue;
}
TmfXmlLocation location = modelFactory.createLocation(element, this);
locations.add(location);
}
fLocations = Collections.unmodifiableSet(locations);
/* parser for the mapping groups */
final @NonNull Map<@NonNull String, @NonNull Set<@NonNull TmfXmlMapEntry>> mapGroups = new HashMap<>();
NodeList mapNodes = doc.getElementsByTagName(TmfXmlStrings.MAPPING_GROUP);
for (int i = 0; i < mapNodes.getLength(); i++) {
Element map = (Element) mapNodes.item(i);
String id = map.getAttribute(TmfXmlStrings.ID);
Set<@NonNull TmfXmlMapEntry> entrySet = mapGroups.get(id);
if (entrySet == null) {
entrySet = new HashSet<>();
mapGroups.put(id, entrySet);
}
NodeList entryNodes = map.getElementsByTagName(TmfXmlStrings.ENTRY);
for (int j = 0; j < entryNodes.getLength(); j++) {
Element entryElement = (Element) entryNodes.item(j);
if (entryElement == null) {
continue;
}
TmfXmlMapEntry entry = modelFactory.createMapEntry(entryElement, this);
entrySet.add(entry);
}
}
fMappingGroups = Collections.unmodifiableMap(mapGroups);
/* parser for the event handlers */
childElements = XmlUtils.getChildElements(doc, TmfXmlStrings.EVENT_HANDLER);
for (Element element : childElements) {
if (element == null) {
continue;
}
TmfXmlEventHandler handler = modelFactory.createEventHandler(element, this);
fEventHandlers.add(handler);
}
}
/**
* Get the state id of the state provider
*
* @return The state id of the state provider
*/
@NonNull
public String getStateId() {
return fStateId;
}
// ------------------------------------------------------------------------
// IStateChangeInput
// ------------------------------------------------------------------------
@Override
public int getVersion() {
Element ssNode = XmlUtils.getElementInFile(fFilePath.makeAbsolute().toOSString(), TmfXmlStrings.STATE_PROVIDER, fStateId);
if (ssNode != null) {
return Integer.parseInt(ssNode.getAttribute(TmfXmlStrings.VERSION));
}
/*
* The version attribute is mandatory and XML files that don't validate
* with the XSD are ignored, so this should never happen
*/
throw new IllegalStateException("The state provider XML node should have a version attribute"); //$NON-NLS-1$
}
@Override
public XmlStateProvider getNewInstance() {
return new XmlStateProvider(this.getTrace(), getStateId(), fFilePath);
}
@Override
protected void eventHandle(ITmfEvent event) {
for (TmfXmlEventHandler eventHandler : fEventHandlers) {
eventHandler.handleEvent(event);
}
}
@Override
public ITmfStateSystem getStateSystem() {
return getStateSystemBuilder();
}
// ------------------------------------------------------------------------
// Operations
// ------------------------------------------------------------------------
@Override
public Iterable<TmfXmlLocation> getLocations() {
return fLocations;
}
/**
* Get the defined value associated with a constant
*
* @param constant
* The constant defining this value
* @return The actual value corresponding to this constant
*/
public String getDefinedValue(String constant) {
return fDefinedValues.get(constant);
}
@Override
public String getAttributeValue(String name) {
String attribute = name;
if (attribute.startsWith(TmfXmlStrings.VARIABLE_PREFIX)) {
/* search the attribute in the map without the fist character $ */
attribute = getDefinedValue(attribute.substring(1));
}
return attribute;
}
/**
* Get the list of state value handlers defined in this top level element
*
* @param id
* The mapping group id
* @return The set of {@link TmfXmlMapEntry}
*/
public @Nullable Set<@NonNull TmfXmlMapEntry> getMappingGroup(@NonNull String id) {
return fMappingGroups.get(id);
}
}