1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.  Oracle designates this
  10  * particular file as subject to the "Classpath" exception as provided
  11  * by Oracle in the LICENSE file that accompanied this code.
  12  *
  13  * This code is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16  * version 2 for more details (a copy is included in the LICENSE file that
  17  * accompanied this code).
  18  *
  19  * You should have received a copy of the GNU General Public License version
  20  * 2 along with this work; if not, write to the Free Software Foundation,
  21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  22  *
  23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  24  * or visit www.oracle.com if you need additional information or have any
  25  * questions.
  26  */
  27 package com.sun.javatest.report;
  28 
  29 import com.sun.interview.ChoiceArrayQuestion;
  30 import com.sun.interview.ChoiceQuestion;
  31 import com.sun.interview.FileListQuestion;
  32 import com.sun.interview.PropertiesQuestion;
  33 import com.sun.interview.Question;
  34 import com.sun.interview.StringListQuestion;
  35 import com.sun.interview.TreeQuestion;
  36 import com.sun.interview.YesNoQuestion;
  37 import com.sun.javatest.ExcludeList;
  38 import com.sun.javatest.JavaTestError;
  39 import com.sun.javatest.Keywords;
  40 import com.sun.javatest.Parameters;
  41 import com.sun.javatest.Status;
  42 import com.sun.javatest.TemplateUtilities;
  43 import com.sun.javatest.TemplateUtilities.ConfigInfo;
  44 import com.sun.javatest.TestDescription;
  45 import com.sun.javatest.TestEnvironment;
  46 import com.sun.javatest.TestFilter;
  47 import com.sun.javatest.TestResult;
  48 import com.sun.javatest.TestResult.Section;
  49 import com.sun.javatest.TestResultTable;
  50 import com.sun.javatest.WorkDirectory;
  51 import com.sun.javatest.util.I18NResourceBundle;
  52 import java.io.BufferedWriter;
  53 import java.io.File;
  54 import java.io.FileOutputStream;
  55 import java.io.IOException;
  56 import java.io.OutputStreamWriter;
  57 import java.io.Writer;
  58 import java.text.DateFormat;
  59 import java.text.ParseException;
  60 import java.text.SimpleDateFormat;
  61 import java.util.Collections;
  62 import java.util.Date;
  63 import java.util.Enumeration;
  64 import java.util.Iterator;
  65 import java.util.List;
  66 import java.util.Map;
  67 import org.xml.sax.SAXException;
  68 
  69 
  70 /**
  71  * XML report (dump).
  72  */
  73 public class XMLReport  implements ReportFormat {
  74 
  75     @Override
  76     public ReportLink write(ReportSettings sett, File dir) throws IOException {
  77 
  78         File repFile = new File(dir, REPORT_NAME);
  79         Writer w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(repFile), XMLReportMaker.XML_CHARSET));
  80         try {
  81             write(w, sett);
  82         } catch (SAXException ex) {
  83             throw new JavaTestError(i18n.getString("report.writing.err"), ex);
  84         }
  85         w.close();
  86         sett.xmlReportFile = repFile;
  87 
  88         return new ReportLink(i18n.getString("index.xmltype.txt"),
  89                 getBaseDirName(), i18n.getString("index.desc.xml"),repFile);
  90 
  91     }
  92 
  93     @Override
  94     public String getReportID() {
  95         return ID;
  96     }
  97 
  98     @Override
  99     public String getBaseDirName() {
 100         return ID;
 101     }
 102 
 103     @Override
 104     public String getTypeName() {
 105         return ID;
 106     }
 107 
 108     @Override
 109     public boolean acceptSettings(ReportSettings s) {
 110         return s.isXmlEnabled();
 111     }
 112 
 113     @Override
 114     public List<ReportFormat> getSubReports() {
 115         return Collections.<ReportFormat>emptyList();
 116     }
 117 
 118     public void write(Writer w, ReportSettings sett) throws IOException, SAXException {
 119 
 120         XMLReportMaker maker = new XMLReportMaker(w);
 121         maker.sDocument();
 122         maker.sReport();
 123         maker.sWorkdirectories();
 124         File jti = null;
 125         if (sett.getInterview() != null) {
 126             jti = sett.getInterview().getFile();
 127         }
 128         maker.sWorkdirectory( jti == null ? null : jti.getPath());
 129 
 130         writeTemplateInfo(maker, sett);
 131         writeInterview(maker, sett);
 132         writeStandardValues(maker, sett);
 133         writeEnvironment(maker, sett);
 134 
 135         maker.eWorkdirectory();
 136         maker.eWorkdirectories();
 137         writeResults(maker, sett);
 138         maker.eReport();
 139         maker.eDocument();
 140 
 141     }
 142 
 143     private void writeResults(final XMLReportMaker maker, final ReportSettings sett) throws SAXException, JavaTestError, IOException {
 144         maker.sTestResults();
 145 
 146         File[] initFiles = sett.getInitialFiles();
 147         Iterator iter = null;
 148         TestResultTable resultTable = sett.getInterview().getWorkDirectory().getTestResultTable();
 149 
 150         try {
 151             if (initFiles == null) {
 152                 iter = resultTable.getIterator(new TestFilter[] {sett.getTestFilter()});
 153             } else {
 154                 iter = resultTable.getIterator(initFiles, new TestFilter[] {sett.getTestFilter()});
 155             }
 156             for (; iter.hasNext(); ) {
 157                 TestResult tr = (TestResult) (iter.next());
 158                 writeResult(maker, tr);
 159             }
 160             maker.eTestResults();
 161         } catch (TestResultTable.Fault f) {
 162             throw new JavaTestError(i18n.getString("report.testResult.err"), f);
 163         }
 164     }
 165 
 166     private void writeResult(final XMLReportMaker maker, final TestResult testResult) throws SAXException, IOException {
 167 
 168         maker.sTestResult(testResult.getTestName(), testResult.getStatus(), 1);
 169         try {
 170             writeDescriptionData(maker, testResult);
 171             writeEnvironment(maker, testResult);
 172             writeResultProps(maker, testResult);
 173             writeSections(maker, testResult);
 174             writeAnnotations(maker, testResult);
 175         } catch (TestResult.Fault  e) {
 176             System.err.println(i18n.getString("report.writing.err"));
 177             e.printStackTrace();
 178         } finally {
 179             maker.eTestResult();
 180         }
 181     }
 182 
 183     private void writeSections(final XMLReportMaker maker, final TestResult testResult) throws SAXException, IOException, TestResult.Fault {
 184 
 185         maker.sSections();
 186         for (int i = 0; i < testResult.getSectionCount() ; i++) {
 187             String st = testResult.getSectionTitles()[i];
 188             Section sec = testResult.getSection(i);
 189             Status stat = sec.getStatus();
 190             maker.sSection(st, stat);
 191             for (int j=0; j < sec.getOutputCount(); j++) {
 192                 String oName = sec.getOutputNames()[j];
 193                 maker.sOutput(oName, sec.getOutput(oName));
 194                 maker.eOutput();
 195             }
 196             maker.eSection();
 197         }
 198         maker.eSections();
 199     }
 200 
 201     private void writeResultProps(final XMLReportMaker maker, final TestResult testResult) throws SAXException, TestResult.Fault {
 202 
 203         String time = testResult.getProperty(TestResult.END);
 204 
 205         maker.sResultProps(time);
 206         Enumeration en = testResult.getPropertyNames();
 207         while (en.hasMoreElements()) {
 208             String key = (String) en.nextElement();
 209             String val = testResult.getProperty(key);
 210             if (!TestResult.END.equals(key)) {
 211                 maker.makeProperty(key, val);
 212             }
 213         }
 214         maker.eResultProps();
 215     }
 216 
 217     private void writeEnvironment(final XMLReportMaker maker, final TestResult testResult) throws SAXException {
 218 
 219         Iterator keysIt;
 220         try {
 221             Map m = testResult.getEnvironment();
 222             keysIt =  m.keySet().iterator();
 223             maker.sTestEnvironment();
 224             while (keysIt.hasNext()) {
 225                 String key = (String) keysIt.next();
 226                 String val = (String) m.get(key);
 227                 maker.makeProperty(key, val);
 228             }
 229             maker.eTestEnvironment();
 230         } catch (TestResult.Fault e) {
 231 
 232         }
 233     }
 234 
 235     private void writeDescriptionData(final XMLReportMaker maker, final TestResult testResult) throws SAXException, TestResult.Fault {
 236         maker.sDescriptionData();
 237 
 238         TestDescription td = testResult.getDescription();
 239         Iterator<String> keysIt = td.getParameterKeys();
 240 
 241         maker.makeProperty("$root", td.getRootDir());
 242         maker.makeProperty("$file", td.getFile().getPath());
 243 
 244         while (keysIt.hasNext()) {
 245             String key = keysIt.next();
 246             // dump keywords separately
 247             if (!"keywords".equals(key)) {
 248                 String val = td.getParameter(key);
 249                 maker.makeProperty(key, val);
 250             }
 251         }
 252 
 253         String [] kws = td.getKeywords();
 254         if (kws != null && kws.length > 0 ) {
 255             maker.sKeyWords();
 256             maker.makeItems(kws);
 257             maker.eKeyWords();
 258         }
 259         maker.eDescriptionData();
 260     }
 261 
 262     private void writeAnnotations(XMLReportMaker maker, TestResult testResult) throws SAXException {
 263         TestResultTable.TreeNode tn = testResult.getParent();
 264         TestResultTable trt = null;
 265         WorkDirectory wd = null;
 266 
 267         if (tn != null)
 268             trt = tn.getEnclosingTable();
 269         else
 270             return;
 271 
 272         if (trt != null)
 273             wd = trt.getWorkDirectory();
 274         else
 275             return;
 276 
 277         Map<String,String> map = wd.getTestAnnotations(testResult);
 278         if (map != null) {
 279             maker.sTAnnotationData();
 280             for (String key: map.keySet()) {
 281                 maker.makeProperty(key, map.get(key));
 282             }   // for
 283             maker.eTAnnotationData();
 284         }
 285     }
 286 
 287     private void writeEnvironment(final XMLReportMaker maker, final ReportSettings sett) throws SAXException {
 288 
 289         String name = null, descr = null;
 290 
 291         if (sett.getInterview().getEnv() != null) {
 292             name = sett.getInterview().getEnv().getName();
 293             descr= sett.getInterview().getEnv().getDescription();
 294         }
 295 
 296         maker.sEnvironment(name, descr);
 297         TestEnvironment env = sett.getInterview().getEnv();
 298         if (env != null) {
 299             for (Iterator i = env.elements().iterator(); i.hasNext(); ) {
 300                 TestEnvironment.Element envElem = (TestEnvironment.Element) (i.next());
 301                 maker.makeProperty(envElem.getKey(), envElem.getValue());
 302             }
 303         }
 304         maker.eEnvironment();
 305     }
 306 
 307     private void writeStandardValues(final XMLReportMaker maker, ReportSettings sett) throws SAXException {
 308         maker.sStdValues();
 309         writeTestsToRun(maker, sett);
 310         writePriorStatusList(maker, sett);
 311         writeExcludeLists(maker, sett);
 312         maker.conCur(sett.getInterview().getConcurrency());
 313         maker.timeOut(sett.getInterview().getTimeoutFactor());
 314         writeKeyWords(maker, sett);
 315         maker.eStdValues();
 316     }
 317 
 318     private void writeKeyWords(final XMLReportMaker maker, final ReportSettings sett) throws SAXException {
 319         // keywords
 320         Keywords keywords = sett.getInterview().getKeywords();
 321         if (keywords != null) {
 322             maker.sKeyWords(sett.getInterview().getKeywords().toString());
 323             maker.eKeyWords();
 324         }
 325     }
 326 
 327     private void writeExcludeLists(final XMLReportMaker maker, final ReportSettings sett) throws SAXException {
 328         // Exclude
 329         ExcludeList excludeList = sett.getInterview().getExcludeList();
 330         if (excludeList != null) {
 331             Parameters.ExcludeListParameters exclParams = sett.getInterview().getExcludeListParameters();
 332             File[] excludeFiles = null;
 333             if (exclParams instanceof Parameters.MutableExcludeListParameters)
 334                 excludeFiles =
 335                         ((Parameters.MutableExcludeListParameters) (exclParams)).getExcludeFiles();
 336 
 337             if (excludeFiles != null && excludeFiles.length > 0) {
 338                 maker.sExclList();
 339                 maker.makeItems(excludeFiles);
 340                 maker.eExclList();
 341             }
 342         }
 343     }
 344 
 345     private void writePriorStatusList(final XMLReportMaker maker, final ReportSettings sett) throws SAXException {
 346         boolean[] b = sett.getInterview().getPriorStatusValues();
 347         if (b != null) {
 348             int[] ss = {Status.PASSED, Status.FAILED, Status.ERROR, Status.NOT_RUN};
 349             maker.sPriorStatusList();
 350             for (int i = 0; i < b.length; i++) {
 351                 if (b[i]) {
 352                     maker.makeItem(Utils.statusIntToString(ss[i]));
 353                 }
 354             }
 355             maker.ePriorStatusList();
 356         }
 357     }
 358 
 359     private void writeTestsToRun(final XMLReportMaker maker, final ReportSettings sett) throws SAXException {
 360         maker.sTests();
 361         String [] tests = sett.getInterview().getTests();
 362         if (tests != null && tests.length > 0) {
 363             for (int i = 0; i < tests.length; i++) {
 364                 maker.makeItem(tests[i]);
 365             }
 366         } else {
 367             maker.makeEntireTestTree();
 368         }
 369         maker.eTests();
 370     }
 371 
 372     private void writeTemplateInfo(final XMLReportMaker maker, final ReportSettings sett) throws SAXException {
 373         String tPath = sett.getInterview().getTemplatePath();
 374         if (tPath != null) {
 375             try {
 376                 ConfigInfo ci = TemplateUtilities.getConfigInfo(new File(tPath));
 377                 maker.makeTemplateInfo(tPath, ci.getName(), ci.getDescription());
 378             } catch (IOException ex) {
 379                 // do nothing
 380             }
 381         }
 382     }
 383 
 384 
 385     private void writeInterview(final XMLReportMaker maker, final ReportSettings sett) throws SAXException {
 386 
 387         maker.sInterview();
 388         Question [] questions = sett.getInterview().getPath();
 389         for (int i = 0; i < questions.length; i++) {
 390             Question q = questions[i];
 391             maker.sQuestion(q.getStringValue(), q.getText(), q.getSummary());
 392             if (q instanceof TreeQuestion || q instanceof StringListQuestion || q instanceof FileListQuestion) {
 393                 writeListQuestion(maker, q);
 394             } else if (q instanceof ChoiceQuestion || q instanceof YesNoQuestion || q instanceof ChoiceArrayQuestion) {
 395                 writeChoiceQuestion(maker, q);
 396             } else if (q instanceof PropertiesQuestion) {
 397                 writePropertiesQuestion(maker, q);
 398             }
 399             maker.eQuestion();
 400         }
 401         maker.eInterview();
 402     }
 403 
 404     private void writeListQuestion(XMLReportMaker maker, Question q) throws SAXException {
 405         maker.sListQuestion();
 406         if (q instanceof TreeQuestion) {
 407             TreeQuestion tq = (TreeQuestion) q;
 408             maker.makeItems(tq.getValue());
 409         } else if (q instanceof StringListQuestion ) {
 410             StringListQuestion slq = (StringListQuestion) q;
 411             maker.makeItems(slq.getValue());
 412         } else if (q instanceof FileListQuestion) {
 413             FileListQuestion flq = (FileListQuestion) q;
 414             maker.makeItems(flq.getValue());
 415         }
 416         maker.eListQuestion();
 417     }
 418 
 419     private void writePropertiesQuestion(XMLReportMaker maker, Question q) throws SAXException {
 420         maker.sPropertiesQuestion();
 421         PropertiesQuestion pq = (PropertiesQuestion) q;
 422         String [] grs = pq.getGroups();
 423         String h1 = pq.getKeyHeaderName();
 424         String h2 = pq.getValueHeaderName();
 425         if (grs != null) {
 426             for (int i = 0; i < grs.length; i++) {
 427                 String name = grs[i];
 428                 maker.sGroup(name, h1, h2);
 429                 if (name != null) {
 430                     String[][] table = pq.getGroup(name);
 431                     writeTable(maker, table);
 432                 }
 433                 maker.eGroup(name, h1, h2);
 434             }
 435         }
 436         maker.ePropertiesQuestion();
 437     }
 438 
 439     private void writeChoiceQuestion(XMLReportMaker maker, Question q) throws SAXException {
 440         maker.sChoiceQuestion();
 441         if (q instanceof ChoiceQuestion ) {
 442             ChoiceQuestion cq = (ChoiceQuestion) q;
 443             maker.makeChoices(cq.getChoices(), cq.getDisplayChoices());
 444         } else if (q instanceof YesNoQuestion ) {
 445             YesNoQuestion ynq = (YesNoQuestion) q;
 446             maker.makeChoices(ynq.getChoices(), ynq.getDisplayChoices());
 447         } else if (q instanceof ChoiceArrayQuestion) {
 448             ChoiceArrayQuestion caq = (ChoiceArrayQuestion) q;
 449             maker.makeChoices(caq.getChoices(), caq.getDisplayChoices(), caq.getValue());
 450         }
 451         maker.eChoiceQuestion();
 452     }
 453 
 454     private void writeTable(XMLReportMaker maker, String[][] table) throws SAXException {
 455         if (table != null ) {
 456             for (int i=0 ; i < table.length ;i++) {
 457                 maker.makeRow(table[i][0], table[i][1]);
 458             }
 459         }
 460     }
 461 
 462     /**
 463      * Utility class
 464      */
 465     static class Utils {
 466 
 467         /**
 468          * Convert date to string in ISO-8601 or xs:dateTime format
 469          * @param date Date
 470          * @return ISO-8601 String
 471          */
 472         static String dateToISO8601(Date date) {
 473             DateFormat dfISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
 474             // format in (almost) ISO8601 format
 475             String dateStr = dfISO8601.format(date);
 476             // remap the timezone from 0000 to 00:00 (starts at char 22)
 477             return dateStr.substring(0, 22) + ":" + dateStr.substring(22);
 478         }
 479 
 480         /**
 481          * Convert string from JTR format to java.util.Date
 482          * @throws java.text.ParseException
 483          * @param dateStr String
 484          * @return Date
 485          */
 486         static Date jtrToDate(String dateStr) throws ParseException {
 487             return TestResult.parseDate(dateStr);
 488         }
 489 
 490         /**
 491          * Convert Status object to String
 492          */
 493         static String statusToString(Status st) {
 494             if (st.isError()) return "ERROR";
 495             if (st.isFailed()) return "FAILED";
 496             if (st.isNotRun()) return "NOT_RUN";
 497             if (st.isPassed()) return "PASSED";
 498             return "UNKNOWN";
 499         }
 500 
 501         /**
 502          * Convert Status integer value to String
 503          */
 504         static String statusIntToString(int st) {
 505             if (st == Status.ERROR) return "ERROR";
 506             if (st == Status.FAILED) return "FAILED";
 507             if (st == Status.NOT_RUN) return "NOT_RUN";
 508             if (st == Status.PASSED) return "PASSED";
 509             return "UNKNOWN";
 510         }
 511 
 512     }
 513 
 514     private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(XMLReport.class);
 515 
 516     // The name of the root file for a set of report files.
 517     static final String REPORT_NAME = "report.xml";
 518 
 519     private static final String ID = "xml";
 520 
 521 }