/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.motorolamobility.preflighting.internal.commandoutput;
import java.io.File;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.xerces.jaxp.DocumentBuilderFactoryImpl;
import org.eclipse.core.runtime.IStatus;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.motorolamobility.preflighting.core.exception.PreflightingToolException;
import com.motorolamobility.preflighting.core.logging.PreflightingLogger;
import com.motorolamobility.preflighting.core.utils.XmlUtils;
import com.motorolamobility.preflighting.core.validation.ApplicationValidationResult;
import com.motorolamobility.preflighting.core.validation.Parameter;
import com.motorolamobility.preflighting.core.validation.ValidationManagerConfiguration;
import com.motorolamobility.preflighting.core.validation.ValidationResult;
import com.motorolamobility.preflighting.core.validation.ValidationResultData;
import com.motorolamobility.preflighting.core.validation.ValidationResultData.SEVERITY;
import com.motorolamobility.preflighting.core.verbose.WarningLevelFilter;
import com.motorolamobility.preflighting.i18n.PreflightingNLS;
import com.motorolamobility.preflighting.internal.PreflightingPlugin;
import com.motorolamobility.preflighting.output.AbstractOutputter;
public class XmlOutputter extends AbstractOutputter
{
protected Document document = null;
private static final String XML_TAG_APP_VALIDATOR = "AppValidator";
private static final String XML_TAG_APPLICATION = "Application";
private static final String XML_TAG_ERROR = "Error";
private static final String XML_TAG_FATAL_ERROR = "FatalError";
private static final String XML_TAG_WARNING = "Warning";
private static final String XML_TAG_RESOURCE = "Resource";
private static final String XML_TAG_LINE = "Line";
private static final String XML_TAG_SUGGESTION = "Suggestion";
private static final String XML_ATTRIBUTE_CHECKER_ID = "checker_id";
private static final String XML_ATTRIBUTE_CONDITION_ID = "condition_id";
private static final String XML_ATTRIBUTE_INFO_URL = "info_url";
private static final String XML_ATTRIBUTE_PATH = "path";
private static final String XML_ATTRIBUTE_APP_NAME = "app_name";
private static final String XML_TAG_DESCRIPTION = "Description";
private static final String XML_TAG_PREVIEW = "Preview";
private static final String XML_ATTRIBUTE_APPVALIDATOR_VERSION = "version";
private static final String XML_ATTRIBUTE_APPLICATION_VERSION = "app_version";
private static final String XML_ATTRIBUTE_MOTODEV_LINK = "description_url";
private static final String XML_CHECKER_STATUS_VALUE_FAIL = "Failed";
private static final String XML_CHECKER_STATUS_VALUE_DISABLED = "Disabled";
private static final String XML_CHECKER_STATUS_VALUE_OK = "Executed";
private static final String XML_ATTRIBUTE_MESSAGE = "message";
private static final String XML_ATTRIBUTE_STATUS = "status";
private static final String XML_TAG_CHECKER_STATUS = "CheckerStatus";
private static final String XML_TAG_EXECUTION_REPORT = "ExecutionReport";
//TODO change tag name
private static final String XML_TAG_APP_VALIDATOR_EXECUTION_REPORT = "ExecutionReport";
private static final String XML_TAG_MESSAGES = "Messages";
/**
* Writes to file xml or text in the following format: <br>
* <type (Error/Warning/Info)> <number files involved (Java, XML)> <filePath1 (without OS specific characters)>:<linePath1> ... <filePathN>:<linePathN> <description>
* @throws PreflightingToolException
*/
@Override
public void print(ApplicationValidationResult result, OutputStream stream,
List<Parameter> parameters) throws PreflightingToolException
{
initializeParams(parameters);
try
{
Element appValElem = createRootNode();
Element applicationElem = document.createElement(XML_TAG_APPLICATION);
applicationElem.setAttribute(XML_ATTRIBUTE_APP_NAME, getApplicationFile().getName());
applicationElem.setAttribute(XML_ATTRIBUTE_APPLICATION_VERSION,
String.valueOf(result.getVersion()));
generateCustomApplicationNodes(applicationElem, result, parameters);
appValElem.appendChild(applicationElem);
Element messagesElement = document.createElement(XML_TAG_MESSAGES);
applicationElem.appendChild(messagesElement);
//create result nodes and append them to document
generateResultNodes(messagesElement, result.getResults());
generateExecutionReport(applicationElem, result.getExecutionStatus());
//create XML output
XmlUtils.printXMLFormat(document);
}
catch (Exception e)
{
PreflightingLogger.error(getClass(), PreflightingNLS.TextOutputter_IOExceptionMessage
+ e.getMessage());
throw new PreflightingToolException(
PreflightingNLS.XMLOutputter_PrintResultsErrorMessage, e);
}
}
/*
* Generates the nodes for the result list
*/
private void generateResultNodes(Element rootElement, List<ValidationResult> result)
{
for (ValidationResult checker : result)
{
for (ValidationResultData data : checker.getValidationResult())
{
if (SEVERITY.OK.compareTo(data.getSeverity()) != 0)
{
Element issueElement = createIssueNode(data.getSeverity());
issueElement.setAttribute(XML_ATTRIBUTE_CHECKER_ID, checker.getCheckerId());
issueElement.setAttribute(XML_ATTRIBUTE_CONDITION_ID, data.getConditionID());
if (data.getInfoURL() != null)
{
issueElement.setAttribute(XML_ATTRIBUTE_INFO_URL, data.getInfoURL());
}
Element descriptionElement = createDescriptionNode(data.getIssueDescription());
issueElement.appendChild(descriptionElement);
for (File currentFile : data.getFileToIssueLines().keySet())
{
Element resourceElement =
createResourceNode(currentFile,
data.getFileToIssueLines().get(currentFile));
issueElement.appendChild(resourceElement);
}
if (WarningLevelFilter.printQuickFixSuggestions())
{
Element suggestionElement =
createSuggestionNode(data.getQuickFixSuggestion());
issueElement.appendChild(suggestionElement);
}
if (data.getPreview() != null)
{
Element previewElement = createPreviewNode(data.getPreview());
issueElement.appendChild(previewElement);
}
rootElement.appendChild(issueElement);
}
}
}
}
/*
* Generate the execution report node based on contents from executionStatus map
*/
private void generateExecutionReport(Element appValElem, Map<String, IStatus> executionStatus)
{
Element executionReportElement = document.createElement(XML_TAG_EXECUTION_REPORT);
for (String checkerId : executionStatus.keySet())
{
IStatus checkerStatus = executionStatus.get(checkerId);
Element checkerStatusElement = document.createElement(XML_TAG_CHECKER_STATUS);
checkerStatusElement.setAttribute(XML_ATTRIBUTE_CHECKER_ID, checkerId);
//checker status equal INFO will be displayed as not executed
String status;
switch (checkerStatus.getSeverity())
{
case IStatus.OK:
status = XML_CHECKER_STATUS_VALUE_OK;
break;
case IStatus.INFO:
status = XML_CHECKER_STATUS_VALUE_DISABLED;
break;
default: //failed
status = XML_CHECKER_STATUS_VALUE_FAIL;
break;
}
checkerStatusElement.setAttribute(XML_ATTRIBUTE_STATUS, status);
checkerStatusElement.setAttribute(XML_ATTRIBUTE_MESSAGE, checkerStatus.getMessage());
executionReportElement.appendChild(checkerStatusElement);
}
appValElem.appendChild(executionReportElement);
}
/*
* ERROR, FATAL_ERROR or WARNING nodes
*/
private Element createIssueNode(SEVERITY severity)
{
Element element = null;
if (SEVERITY.ERROR.compareTo(severity) == 0)
{
element = document.createElement(XML_TAG_ERROR);
}
else if (SEVERITY.WARNING.compareTo(severity) == 0)
{
element = document.createElement(XML_TAG_WARNING);
}
else if (SEVERITY.FATAL.compareTo(severity) == 0)
{
element = document.createElement(XML_TAG_FATAL_ERROR);
}
return element;
}
/*
* Issue description node
*/
private Element createDescriptionNode(String description)
{
Element element = document.createElement(XML_TAG_DESCRIPTION);
if (description != null)
{
element.setTextContent(description);
}
return element;
}
/**
* Create resource node
* @param currentFile (resource)
* @param lines with errors in this resource
* @return the resource node
*/
private Element createResourceNode(File currentFile, List<Integer> lines)
{
Element resElement = document.createElement(XML_TAG_RESOURCE);
resElement.setAttribute(XML_ATTRIBUTE_PATH, computeResourcePath(currentFile));
for (Integer currentLine : lines)
{
Element lineElement = document.createElement(XML_TAG_LINE);
lineElement.setTextContent(currentLine.toString());
resElement.appendChild(lineElement);
}
return resElement;
}
/**
* Create fix sugestion node
* @param suggestion text
* @return the sugestion node
*/
private Element createSuggestionNode(String suggestion)
{
Element sugElement = document.createElement(XML_TAG_SUGGESTION);
sugElement.setTextContent(suggestion);
return sugElement;
}
/**
* Create a Preview node with Validation preview
* @param preview text
* @return preview node
*/
private Element createPreviewNode(String preview)
{
Element previewElement = document.createElement(XML_TAG_PREVIEW);
previewElement.setTextContent(preview);
return previewElement;
}
@Override
public void printError(Exception exceptionThrown, PrintStream out)
{
try
{
Element appValElem = createRootNode();
Element executionReportElement =
document.createElement(XML_TAG_APP_VALIDATOR_EXECUTION_REPORT);
executionReportElement
.setAttribute(XML_ATTRIBUTE_STATUS, XML_CHECKER_STATUS_VALUE_FAIL);
executionReportElement
.setAttribute(XML_ATTRIBUTE_MESSAGE, exceptionThrown.getMessage());
appValElem.appendChild(executionReportElement);
XmlUtils.printXMLFormat(document);
}
catch (Exception e)
{
PreflightingLogger.error(getClass(),
PreflightingNLS.XMLOutputter_PrintResultsErrorMessage + e.getMessage());
}
}
//creates the document and its root node
private Element createRootNode() throws ParserConfigurationException
{
document = DocumentBuilderFactoryImpl.newInstance().newDocumentBuilder().newDocument();
Element appValElem = document.createElement(XML_TAG_APP_VALIDATOR);
document.appendChild(appValElem);
String appValidatorVersion = PreflightingPlugin.getInstance().getAppValidatorVersion();
ValidationManagerConfiguration valManagerConfiguration =
ValidationManagerConfiguration.getInstance();
String motodevLink =
valManagerConfiguration
.getProperty(ValidationManagerConfiguration.ConfigProperties.BASE_URL_PROPERTY
.getName());
appValElem.setAttribute(XML_ATTRIBUTE_APPVALIDATOR_VERSION, appValidatorVersion);
appValElem.setAttribute(XML_ATTRIBUTE_MOTODEV_LINK, motodevLink);
return appValElem;
}
protected void generateCustomApplicationNodes(Element applicationElem,
ApplicationValidationResult result, List<Parameter> params)
{
//Do nothing.
}
}