1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.motorolamobility.preflighting.internal.commandoutput; 17 18 import java.io.File; 19 import java.io.OutputStream; 20 import java.io.PrintStream; 21 import java.util.List; 22 import java.util.Map; 23 24 import javax.xml.parsers.ParserConfigurationException; 25 26 import org.apache.xerces.jaxp.DocumentBuilderFactoryImpl; 27 import org.eclipse.core.runtime.IStatus; 28 import org.w3c.dom.Document; 29 import org.w3c.dom.Element; 30 31 import com.motorolamobility.preflighting.core.exception.PreflightingToolException; 32 import com.motorolamobility.preflighting.core.logging.PreflightingLogger; 33 import com.motorolamobility.preflighting.core.utils.XmlUtils; 34 import com.motorolamobility.preflighting.core.validation.ApplicationValidationResult; 35 import com.motorolamobility.preflighting.core.validation.Parameter; 36 import com.motorolamobility.preflighting.core.validation.ValidationManagerConfiguration; 37 import com.motorolamobility.preflighting.core.validation.ValidationResult; 38 import com.motorolamobility.preflighting.core.validation.ValidationResultData; 39 import com.motorolamobility.preflighting.core.validation.ValidationResultData.SEVERITY; 40 import com.motorolamobility.preflighting.core.verbose.WarningLevelFilter; 41 import com.motorolamobility.preflighting.i18n.PreflightingNLS; 42 import com.motorolamobility.preflighting.internal.PreflightingPlugin; 43 import com.motorolamobility.preflighting.output.AbstractOutputter; 44 45 public class XmlOutputter extends AbstractOutputter 46 { 47 48 protected Document document = null; 49 50 private static final String XML_TAG_APP_VALIDATOR = "AppValidator"; 51 52 private static final String XML_TAG_APPLICATION = "Application"; 53 54 private static final String XML_TAG_ERROR = "Error"; 55 56 private static final String XML_TAG_FATAL_ERROR = "FatalError"; 57 58 private static final String XML_TAG_WARNING = "Warning"; 59 60 private static final String XML_TAG_RESOURCE = "Resource"; 61 62 private static final String XML_TAG_LINE = "Line"; 63 64 private static final String XML_TAG_SUGGESTION = "Suggestion"; 65 66 private static final String XML_ATTRIBUTE_CHECKER_ID = "checker_id"; 67 68 private static final String XML_ATTRIBUTE_CONDITION_ID = "condition_id"; 69 70 private static final String XML_ATTRIBUTE_INFO_URL = "info_url"; 71 72 private static final String XML_ATTRIBUTE_PATH = "path"; 73 74 private static final String XML_ATTRIBUTE_APP_NAME = "app_name"; 75 76 private static final String XML_TAG_DESCRIPTION = "Description"; 77 78 private static final String XML_TAG_PREVIEW = "Preview"; 79 80 private static final String XML_ATTRIBUTE_APPVALIDATOR_VERSION = "version"; 81 82 private static final String XML_ATTRIBUTE_APPLICATION_VERSION = "app_version"; 83 84 private static final String XML_ATTRIBUTE_MOTODEV_LINK = "description_url"; 85 86 private static final String XML_CHECKER_STATUS_VALUE_FAIL = "Failed"; 87 88 private static final String XML_CHECKER_STATUS_VALUE_DISABLED = "Disabled"; 89 90 private static final String XML_CHECKER_STATUS_VALUE_OK = "Executed"; 91 92 private static final String XML_ATTRIBUTE_MESSAGE = "message"; 93 94 private static final String XML_ATTRIBUTE_STATUS = "status"; 95 96 private static final String XML_TAG_CHECKER_STATUS = "CheckerStatus"; 97 98 private static final String XML_TAG_EXECUTION_REPORT = "ExecutionReport"; 99 100 //TODO change tag name 101 private static final String XML_TAG_APP_VALIDATOR_EXECUTION_REPORT = "ExecutionReport"; 102 103 private static final String XML_TAG_MESSAGES = "Messages"; 104 105 /** 106 * Writes to file xml or text in the following format: <br> 107 * <type (Error/Warning/Info)> <number files involved (Java, XML)> <filePath1 (without OS specific characters)>:<linePath1> ... <filePathN>:<linePathN> <description> 108 * @throws PreflightingToolException 109 */ 110 @Override 111 public void print(ApplicationValidationResult result, OutputStream stream, 112 List<Parameter> parameters) throws PreflightingToolException 113 { 114 initializeParams(parameters); 115 116 try 117 { 118 Element appValElem = createRootNode(); 119 120 Element applicationElem = document.createElement(XML_TAG_APPLICATION); 121 applicationElem.setAttribute(XML_ATTRIBUTE_APP_NAME, getApplicationFile().getName()); 122 applicationElem.setAttribute(XML_ATTRIBUTE_APPLICATION_VERSION, 123 String.valueOf(result.getVersion())); 124 125 generateCustomApplicationNodes(applicationElem, result, parameters); 126 appValElem.appendChild(applicationElem); 127 128 Element messagesElement = document.createElement(XML_TAG_MESSAGES); 129 applicationElem.appendChild(messagesElement); 130 131 //create result nodes and append them to document 132 generateResultNodes(messagesElement, result.getResults()); 133 134 generateExecutionReport(applicationElem, result.getExecutionStatus()); 135 136 //create XML output 137 XmlUtils.printXMLFormat(document); 138 } 139 catch (Exception e) 140 { 141 PreflightingLogger.error(getClass(), PreflightingNLS.TextOutputter_IOExceptionMessage 142 + e.getMessage()); 143 throw new PreflightingToolException( 144 PreflightingNLS.XMLOutputter_PrintResultsErrorMessage, e); 145 } 146 } 147 148 /* 149 * Generates the nodes for the result list 150 */ 151 private void generateResultNodes(Element rootElement, List<ValidationResult> result) 152 { 153 for (ValidationResult checker : result) 154 { 155 for (ValidationResultData data : checker.getValidationResult()) 156 { 157 if (SEVERITY.OK.compareTo(data.getSeverity()) != 0) 158 { 159 Element issueElement = createIssueNode(data.getSeverity()); 160 issueElement.setAttribute(XML_ATTRIBUTE_CHECKER_ID, checker.getCheckerId()); 161 issueElement.setAttribute(XML_ATTRIBUTE_CONDITION_ID, data.getConditionID()); 162 if (data.getInfoURL() != null) 163 { 164 issueElement.setAttribute(XML_ATTRIBUTE_INFO_URL, data.getInfoURL()); 165 } 166 Element descriptionElement = createDescriptionNode(data.getIssueDescription()); 167 issueElement.appendChild(descriptionElement); 168 169 for (File currentFile : data.getFileToIssueLines().keySet()) 170 { 171 Element resourceElement = 172 createResourceNode(currentFile, 173 data.getFileToIssueLines().get(currentFile)); 174 issueElement.appendChild(resourceElement); 175 } 176 177 if (WarningLevelFilter.printQuickFixSuggestions()) 178 { 179 Element suggestionElement = 180 createSuggestionNode(data.getQuickFixSuggestion()); 181 issueElement.appendChild(suggestionElement); 182 } 183 184 if (data.getPreview() != null) 185 { 186 Element previewElement = createPreviewNode(data.getPreview()); 187 issueElement.appendChild(previewElement); 188 } 189 190 rootElement.appendChild(issueElement); 191 } 192 } 193 } 194 } 195 196 /* 197 * Generate the execution report node based on contents from executionStatus map 198 */ 199 private void generateExecutionReport(Element appValElem, Map<String, IStatus> executionStatus) 200 { 201 Element executionReportElement = document.createElement(XML_TAG_EXECUTION_REPORT); 202 203 for (String checkerId : executionStatus.keySet()) 204 { 205 IStatus checkerStatus = executionStatus.get(checkerId); 206 Element checkerStatusElement = document.createElement(XML_TAG_CHECKER_STATUS); 207 208 checkerStatusElement.setAttribute(XML_ATTRIBUTE_CHECKER_ID, checkerId); 209 210 //checker status equal INFO will be displayed as not executed 211 String status; 212 switch (checkerStatus.getSeverity()) 213 { 214 case IStatus.OK: 215 status = XML_CHECKER_STATUS_VALUE_OK; 216 break; 217 case IStatus.INFO: 218 status = XML_CHECKER_STATUS_VALUE_DISABLED; 219 break; 220 default: //failed 221 status = XML_CHECKER_STATUS_VALUE_FAIL; 222 break; 223 } 224 225 checkerStatusElement.setAttribute(XML_ATTRIBUTE_STATUS, status); 226 checkerStatusElement.setAttribute(XML_ATTRIBUTE_MESSAGE, checkerStatus.getMessage()); 227 228 executionReportElement.appendChild(checkerStatusElement); 229 } 230 231 appValElem.appendChild(executionReportElement); 232 } 233 234 /* 235 * ERROR, FATAL_ERROR or WARNING nodes 236 */ 237 private Element createIssueNode(SEVERITY severity) 238 { 239 Element element = null; 240 241 if (SEVERITY.ERROR.compareTo(severity) == 0) 242 { 243 element = document.createElement(XML_TAG_ERROR); 244 } 245 else if (SEVERITY.WARNING.compareTo(severity) == 0) 246 { 247 element = document.createElement(XML_TAG_WARNING); 248 } 249 else if (SEVERITY.FATAL.compareTo(severity) == 0) 250 { 251 element = document.createElement(XML_TAG_FATAL_ERROR); 252 } 253 254 return element; 255 } 256 257 /* 258 * Issue description node 259 */ 260 private Element createDescriptionNode(String description) 261 { 262 Element element = document.createElement(XML_TAG_DESCRIPTION); 263 264 if (description != null) 265 { 266 element.setTextContent(description); 267 } 268 269 return element; 270 } 271 272 /** 273 * Create resource node 274 * @param currentFile (resource) 275 * @param lines with errors in this resource 276 * @return the resource node 277 */ 278 private Element createResourceNode(File currentFile, List<Integer> lines) 279 { 280 Element resElement = document.createElement(XML_TAG_RESOURCE); 281 resElement.setAttribute(XML_ATTRIBUTE_PATH, computeResourcePath(currentFile)); 282 283 for (Integer currentLine : lines) 284 { 285 Element lineElement = document.createElement(XML_TAG_LINE); 286 lineElement.setTextContent(currentLine.toString()); 287 resElement.appendChild(lineElement); 288 } 289 290 return resElement; 291 } 292 293 /** 294 * Create fix sugestion node 295 * @param suggestion text 296 * @return the sugestion node 297 */ 298 private Element createSuggestionNode(String suggestion) 299 { 300 Element sugElement = document.createElement(XML_TAG_SUGGESTION); 301 sugElement.setTextContent(suggestion); 302 303 return sugElement; 304 } 305 306 /** 307 * Create a Preview node with Validation preview 308 * @param preview text 309 * @return preview node 310 */ 311 private Element createPreviewNode(String preview) 312 { 313 Element previewElement = document.createElement(XML_TAG_PREVIEW); 314 previewElement.setTextContent(preview); 315 316 return previewElement; 317 } 318 319 @Override 320 public void printError(Exception exceptionThrown, PrintStream out) 321 { 322 try 323 { 324 Element appValElem = createRootNode(); 325 Element executionReportElement = 326 document.createElement(XML_TAG_APP_VALIDATOR_EXECUTION_REPORT); 327 executionReportElement 328 .setAttribute(XML_ATTRIBUTE_STATUS, XML_CHECKER_STATUS_VALUE_FAIL); 329 executionReportElement 330 .setAttribute(XML_ATTRIBUTE_MESSAGE, exceptionThrown.getMessage()); 331 appValElem.appendChild(executionReportElement); 332 333 XmlUtils.printXMLFormat(document); 334 } 335 catch (Exception e) 336 { 337 PreflightingLogger.error(getClass(), 338 PreflightingNLS.XMLOutputter_PrintResultsErrorMessage + e.getMessage()); 339 } 340 } 341 342 //creates the document and its root node 343 private Element createRootNode() throws ParserConfigurationException 344 { 345 document = DocumentBuilderFactoryImpl.newInstance().newDocumentBuilder().newDocument(); 346 347 Element appValElem = document.createElement(XML_TAG_APP_VALIDATOR); 348 document.appendChild(appValElem); 349 String appValidatorVersion = PreflightingPlugin.getInstance().getAppValidatorVersion(); 350 ValidationManagerConfiguration valManagerConfiguration = 351 ValidationManagerConfiguration.getInstance(); 352 String motodevLink = 353 valManagerConfiguration 354 .getProperty(ValidationManagerConfiguration.ConfigProperties.BASE_URL_PROPERTY 355 .getName()); 356 appValElem.setAttribute(XML_ATTRIBUTE_APPVALIDATOR_VERSION, appValidatorVersion); 357 appValElem.setAttribute(XML_ATTRIBUTE_MOTODEV_LINK, motodevLink); 358 359 return appValElem; 360 } 361 362 protected void generateCustomApplicationNodes(Element applicationElem, 363 ApplicationValidationResult result, List<Parameter> params) 364 { 365 //Do nothing. 366 } 367 } 368