blob: be60a41f577d00cb157341ae93723b0180e91c3c [file] [log] [blame]
/* --COPYRIGHT--,EPL
* Copyright (c) 2008 Texas Instruments and others.
* 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:
* Texas Instruments - initial implementation
*
* --/COPYRIGHT--*/
/*
* ======== MetaData.java ========
*/
package xdc.rta;
import java.util.HashMap;
import java.util.Vector;
import java.util.Set;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Document;
import xdc.rov.TargetType;
/*
* ======== MetaData ========
* Wrapper for the RTA XML file generated for every RTSC application.
*
* The RTA XML file contains information about the application's target,
* loggers, modules, and events. The MetaData class provides APIs for
* accessing this information.
*
* The MetaData object must be initialized using one of the parse APIs.
*/
public class MetaData implements IEventMetaData
{
/* Target information */
private int argSize = -1; // Target arg size in bytes
private int bitsPerChar = -1;
private int eventSize = -1;
private String targetName = "";
private TargetType.Endianess endian;
/* Modules */
private HashMap<Integer, String> modIdToName = null;
private HashMap<String, Integer> modNameToId = null;
private HashMap<String, DiagConfig> modNameToDiags = null;
private HashMap<String, String> modNameToLogger = null;
/* Events */
private HashMap<Integer, String> evtIdToName = null;
private HashMap<String, Integer> evtNameToId = null;
private HashMap<Integer, String> evtIdToMsg = null;
/* Loggers */
private String[] loggerNames = null;
private HashMap<String, Integer> loggerToId = null;
private Vector<Logger> loggers = null;
/* Object file reader for looking up Log_print strings */
private String binaryParserClass = "";
private IOFReader ofReader = null;
/* Class names of data and control transports to use for this app. */
private String dataTransportClassName = "";
private String controlTransportClassName = "";
/*!
* ======== Logger ========
* Contains the properties of a target logger instance.
*/
public class Logger {
public int id;
/* A name to associate with this logger instance. */
public String name;
/* The name of the logger module. */
public String type;
public Node metaArgs;
/* The list of modules which log to this logger. */
public Vector<String> modules;
public Logger()
{
modules = new Vector<String>();
}
}
/*
* ======== getBitsPerChar ========
* Returns the MAU size for this target in bits.
*/
public int getBitsPerChar()
{
return (this.bitsPerChar);
}
/*
* ======== getControlTransportClass ========
*/
public String getControlTransportClass()
{
return (this.controlTransportClassName);
}
/*
* ======== getDataTransportClass ========
*/
public String getDataTransportClass()
{
return (this.dataTransportClassName);
}
/*
* ======== getEndianess ========
*/
public TargetType.Endianess getEndianess()
{
return (this.endian);
}
/*
* ======== getEventNames ========
*/
public String[] getEventNames()
{
Set<String> keys = evtNameToId.keySet();
return (keys.toArray(new String [0]));
}
/*
* ======== getLogger ========
*/
public Logger getLogger(int loggerId)
{
return (loggers.get(loggerId));
}
/*
* ======== getLoggerMetaArgs ========
* Returns the meta data associated with the specified logger instance.
*/
public Node getLoggerMetaArgs(int loggerId)
{
return (loggers.get(loggerId).metaArgs);
}
/*
* ======== getLoggerNames ========
* Lists all the loggers in the system.
*/
public String[] getLoggerNames()
{
return (loggerNames);
}
/*
* ======== getLoggersModules =========
* Returns the list of modules associated with a given logger instance.
*/
public String[] getLoggersModules(String loggerName)
{
int loggerId = lookupLoggerId(loggerName);
Logger logger = this.loggers.get(loggerId);
return (logger.modules.toArray(new String[0]));
}
/*
* ======== getModuleDiagConfig ========
* Gets the initial diagnostics configuration for the given module.
*/
public DiagConfig getModuleDiagConfig(String moduleName) {
return (this.modNameToDiags.get(moduleName));
}
/*
* ======== getModuleLogger ========
* Returns the logger instance associated with the specified module.
*/
public String getModuleLogger(String moduleName) {
return (this.modNameToLogger.get(moduleName));
}
/*
* ======== getModuleNames ========
*/
public String[] getModuleNames()
{
Set<String> keys = modNameToId.keySet();
return (keys.toArray(new String [0]));
}
/*
* ======== getOFReader ========
*/
public IOFReader getOFReader()
{
return (ofReader);
}
/*!
* ======== getProperty ========
* Helper function to retrieve the specified target property from the RTA
* XML file.
*
* These target properties are single XML elements whose values are the
* text content of the element.
*/
public String getProperty(Document doc, String name)
{
/* Retrieve this properties node */
Node n = doc.getElementsByTagName(name).item(0);
Node child = n.getFirstChild();
/* Make sure the XML element isn't empty. */
if (child == null) {
return ("");
}
/* Return the value of this property */
return (child.getNodeValue());
}
public String getProperty(Element elem, String name)
{
/* Retrieve the property node. */
Node n = elem.getElementsByTagName(name).item(0);
Node child = n.getFirstChild();
/* Make sure the XML element isn't empty. */
if (child == null) {
return ("");
}
/* Return the value of this property */
return (child.getNodeValue());
}
/*
* ======== getTargetArgSize ========
* Returns the target size of a record argument in bytes (not MAUs).
*/
public int getTargetArgSize()
{
return (this.argSize);
}
/*
* ======== getTargetEventRecSize ========
* Returns the record size in bytes (not MAUs).
*/
public int getTargetEventRecSize()
{
return (this.eventSize);
}
/*
* ======== getTargetName ========
*/
public String getTargetName()
{
return (this.targetName);
}
/*
* ======== getXMLFromExec ========
* Retrieves the path to a given application's RTA XML file.
*/
public static String getXMLFromExec(String executable) throws Exception
{
return (Recap.locateRecap(executable, ".rta.xml"));
}
/*
* ======== lookupEventId ========
*/
public int lookupEventId(String eventName)
{
Integer res = this.evtNameToId.get(eventName);
return (res == null ? -1 : res);
}
/*
* ======== lookupEventMessage ========
* Returns the format string for the message with the given name.
*/
public String lookupEventMessage(String eventName)
{
return (lookupEventMessage(this.lookupEventId(eventName)));
}
public String lookupEventMessage(int eventId) {
return (this.evtIdToMsg.get(eventId));
}
/*
* ======== lookupEventModule ========
* The event name contains the module name, e.g., xdc.runtime.Log.L_create
*/
public String lookupEventModule(String eventName)
{
return (eventName.substring(0, eventName.lastIndexOf(".")));
}
/*
* ======== lookupEventName ========
*/
public String lookupEventName(int eventId) {
return (this.evtIdToName.get(eventId));
}
/*
* ======== lookupLoggerId ========
*/
public int lookupLoggerId(String loggerName)
{
Integer res = this.loggerToId.get(loggerName);
return (res == null ? -1 : res);
}
/*
* ======== lookupModuleId ========
*/
public int lookupModuleId(String moduleName)
{
Integer res = this.modNameToId.get(moduleName);
return (res == null ? -1 : res);
}
/*
* ======== lookupModuleName ========
*/
public String lookupModuleName(int modId) {
return (this.modIdToName.get(modId));
}
/*
* ======== parse ========
* Initialize the MetaData instance with the given paths to the RTA XML
* file and executable.
*/
public String parse(String xmlFile, String executable)
{
/* Modules */
modNameToId = new HashMap<String, Integer>();
modIdToName = new HashMap<Integer, String>();
modNameToDiags = new HashMap<String, DiagConfig>();
/* Events */
evtNameToId = new HashMap<String, Integer>();
evtIdToName = new HashMap<Integer, String>();
evtIdToMsg = new HashMap<Integer, String>();
/* Loggers */
loggers = new Vector<Logger>();
modNameToLogger = new HashMap<String, String>();
loggerToId = new HashMap<String, Integer>();
Document doc = null;
/* Parse the XML file into a Document object. */
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
doc = builder.parse(new File(xmlFile).toURI().toString());
}
catch (javax.xml.parsers.ParserConfigurationException e) {
return ("Can't create XML parser: " + e.toString());
}
catch (java.io.IOException e) {
return ("Can't read RTA XML file " + xmlFile + ": " + e.toString());
}
catch (org.xml.sax.SAXException e) {
return ("Can't parse RTA XML file " + xmlFile +": " + e.toString());
}
/* Retrieve the target-specific properties */
String res = parseTargetProps(doc);
if (res != "") {
return (res);
}
/* Retrieve the list of loggers and their properties. */
parseLoggers(doc);
/* Retrieve the mapping of modules to ids and the module properties. */
parseModules(doc, xmlFile);
/* Retrieve the event information. */
res = parseEventMap(doc, xmlFile);
if (res != "") {
return (res);
}
/* Initialize the object file reader. */
res = initOfReader(executable);
if (res != "") {
return (res);
}
return ("");
}
/*
* ======== parseFromExec ========
* Retrieves the RTA XML file for the given executable and uses it to
* initialize the MetaData object.
*/
public String parseFromExec(String executable) throws Exception
{
/*
* TODO - Read the parser from the executable using Vers so that
* you can use it to extract the embedded recap file.
*/
/* Retrieve the path to the XML file from the executable. */
String xmlFile = getXMLFromExec(executable);
/* Call parse and return the result. */
String result = parse(xmlFile, executable);
return (result);
}
/*
* ======== initOfReader ========
* Initialize the object file reader used to retrieve Log_print format
* strings.
*
* The object file reader class name comes from the RTA XML file.
*/
private String initOfReader(String executable)
{
/*
* If we don't have the executable, or no binary parser class was
* specified, don't fail; just don't initialize ofReader.
*/
if (executable == null) {
System.out.println("RTA: Executable not specified, cannot " +
"lookup Log_print strings.");
return ("");
}
else if ((this.binaryParserClass == null) ||
(this.binaryParserClass == "")) {
System.out.println("RTA: Binary file parser not specified, " +
"cannot lookup Log_print strings.");
return ("");
}
try {
/* Instantiate the object file reader. */
Class<?> c = Class.forName(this.binaryParserClass);
ofReader = (IOFReader) c.newInstance();
/* Initialize the object file reader. */
String err = ofReader.parse(executable);
if (err != "") {
return("RTA failed to parse " + executable + ": " + err);
}
else {
/*
* Close the file. Reader will re-open it automatically to
* read strings.
*/
ofReader.close();
}
}
catch (IOException e) {
return ("RTA failed to parse object file: " + e);
}
catch (ClassNotFoundException e) {
return ("RTA could not locate the specified binary parser " +
"class: " + e);
}
catch (IllegalAccessException e) {
return ("RTA failed to instantiate binary parser class: " + e);
}
catch (InstantiationException e) {
return ("RTA failed to instantiate binary parser class: " + e);
}
/*
* Set the Formatter's OFReader so that it can perform String
* lookups (%s) when formatting printf strings.
*/
Formatter.setOFReader(ofReader);
/* Return success. */
return ("");
}
/*
* ======== parseEventMap ========
* Helper function to retrieve all of the event information.
*/
private String parseEventMap(Document doc, String xmlFile)
{
/* Get all of the events. */
NodeList evtMap = doc.getElementsByTagName("evtMap");
/* For each event... */
for (int i = 0; i < evtMap.getLength(); i++) {
Element elem = (Element) evtMap.item(i);
/* Get the event's name in the 'key' attribute */
String name = elem.getAttribute("key");
/* Get the event's id. */
int id = Integer.parseInt(getProperty(elem, "id"));
/* Map the event name to id and vice versa. */
this.evtNameToId.put(name, id);
this.evtIdToName.put(id, name);
/* Get the event's message. */
String msg = getProperty(elem, "msg");
/* Map the event id to the event message. */
try {
this.evtIdToMsg.put(id,
java.net.URLDecoder.decode(msg, "UTF-8"));
}
catch (java.io.UnsupportedEncodingException e) {
return ("XMl file " + xmlFile + " contains unsupported " +
"encodings: " + e.toString());
}
}
return ("");
}
/*
* ======== parseLoggers ========
* Retrieve the list of loggers so that we have them in the same
* order as the target.
*/
private void parseLoggers(Document doc)
{
NodeList loggerList = doc.getElementsByTagName("loggers");
for (int i = 0; i < loggerList.getLength(); i++) {
Element elem = (Element) loggerList.item(i);
Logger logger = new Logger();
/* The log's id is its index in the list. */
logger.id = i;
/* Preserve compatibility. Older XML files just have logger name. */
if (elem.getChildNodes().getLength() == 1) {
logger.name = elem.getTextContent();
loggers.add(logger);
this.loggerToId.put(logger.name, i);
continue;
}
/* Get the logger name. */
logger.name = getProperty(elem, "name");
/* Get the logger type. */
logger.type = getProperty(elem, "type");
/* Get the meta args. */
logger.metaArgs = elem.getElementsByTagName("metaArgs").item(0);
/* Map id to logger and logger to id */
loggers.add(logger);
this.loggerToId.put(logger.name, i);
}
/* Create a String array of the logger names for getLoggerNames */
loggerNames = new String[loggers.size()];
for (int i = 0; i < loggers.size(); i++) {
loggerNames[i] = loggers.get(i).name;
}
}
/*!
* ======== parseModules ========
* Parse the modMap, which maps module names to their id, logger,
* and diags settings.
*/
private void parseModules(Document doc, String xmlFile)
{
/* Get all of the module nodes. */
NodeList modMap = doc.getElementsByTagName("modMap");
/* For each module... */
for (int i = 0; i < modMap.getLength(); i++) {
Element elem = (Element) modMap.item(i);
/* Get the module's name which is stored in the 'key' attribute. */
String modName = elem.getAttribute("key");
/* Get the module's id. */
int id = Integer.parseInt(getProperty(elem, "id"));
/* Map the module's id to name and vice versa. */
this.modNameToId.put(modName, id);
this.modIdToName.put(id, modName);
/* Get the module's logger. */
String loggerName = getProperty(elem, "logger");
/*
* Map the module to its logger, but don't map modules with a
* null logger.
*/
if (!loggerName.equals("null")) {
/* Map module name to logger */
this.modNameToLogger.put(modName, loggerName);
/* Map logger to list of modules. */
int loggerId = lookupLoggerId(loggerName);
Logger logger = loggers.get(loggerId);
logger.modules.add(modName);
}
/* Get the module's initial diags mask. */
String diagsMask = getProperty(elem, "diagsMask");
/* Create a DiagConfig object from the mask string */
DiagConfig diags = new DiagConfig(diagsMask);
/* Map the module to its diags mask. */
this.modNameToDiags.put(modName, diags);
}
}
/*!
* ======== parseTargetProps ========
* Helper function to retrieve all of the target properties from the
* RTA XML file.
*/
private String parseTargetProps(Document doc)
{
/* Name of the target. */
this.targetName = getProperty(doc, "targetName");
/* Get the target endianess. */
String endianStr = getProperty(doc, "endian");
/* Convert the endianess to its enum form. */
try {
this.endian = TargetType.strToEndianess(endianStr);
}
catch (Exception e) {
return (e.toString());
}
/* Get the target's MAU size. */
this.bitsPerChar = Integer.parseInt(getProperty(doc, "bitsPerChar"));
/* Get the MAU size of the IArg type, convert it to bytes. */
this.argSize = Integer.parseInt(getProperty(doc, "argSize"));
this.argSize = this.argSize * (this.bitsPerChar / 8);
/* Get the MAU size of an event record, convert it to bytes. */
this.eventSize = Integer.parseInt(getProperty(doc, "eventSize"));
this.eventSize = this.eventSize * (this.bitsPerChar / 8);
/* Get the name of the object file reader class. */
this.binaryParserClass = getProperty(doc, "binaryParser");
/*
* Get the class names of the data and control transport classes to
* use on the host in communicating with this target application.
*
* We need to preserve backwards compatibility with XML files that
* don't contain this information. Check for it before trying to
* retrieve it.
*/
if (doc.getElementsByTagName("dataTransportClassName").getLength() != 0) {
this.dataTransportClassName =
getProperty(doc, "dataTransportClassName");
this.controlTransportClassName =
getProperty(doc, "controlTransportClassName");
}
return ("");
}
}