1/*******************************************************************************
2 * Copyright (c) 2000, 2006 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *     IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.releng.generators;
12
13import java.io.BufferedReader;
14import java.io.File;
15import java.io.FileInputStream;
16import java.io.FileNotFoundException;
17import java.io.FileOutputStream;
18import java.io.FileReader;
19import java.io.IOException;
20import java.io.InputStream;
21import java.util.Arrays;
22import java.util.StringTokenizer;
23import java.util.Vector;
24import java.util.Enumeration;
25
26import org.apache.tools.ant.Task;
27import javax.xml.parsers.DocumentBuilderFactory;
28import javax.xml.parsers.DocumentBuilder;
29import javax.xml.parsers.ParserConfigurationException;
30
31import org.w3c.dom.Document;
32import org.w3c.dom.Element;
33import org.w3c.dom.NamedNodeMap;
34import org.w3c.dom.Node;
35import org.w3c.dom.NodeList;
36import org.xml.sax.InputSource;
37import org.xml.sax.SAXException;
38
39
40/**
41 * @version 	1.0
42 * @author Dean Roberts
43 */
44public class TestResultsGenerator extends Task {
45	private static final String WARNING_SEVERITY = "WARNING";
46	private static final String ERROR_SEVERITY = "ERROR";
47	private static final String ForbiddenReferenceID = "ForbiddenReference";
48	private static final String DiscouragedReferenceID = "DiscouragedReference";
49
50	private static final int DEFAULT_READING_SIZE = 8192;
51
52	static final String elementName = "testsuite";
53	static final String testResultsToken = "%testresults%";
54	static final String compileLogsToken = "%compilelogs%";
55	static final String accessesLogsToken = "%accesseslogs%";
56	public Vector dropTokens;
57	public Vector platformSpecs;
58	public Vector differentPlatforms;
59	public String testResultsWithProblems = "\n";
60	public String testResultsXmlUrls = "\n";
61
62	private DocumentBuilder parser =null;
63	public ErrorTracker anErrorTracker;
64	public String testResultsTemplateString = "";
65	public String dropTemplateString = "";
66
67	public Vector platformDescription;
68	public Vector platformTemplateString;
69	public Vector platformDropFileName;
70
71	//Status of tests results (pending, successful, failed), used to specify the color
72	//of the test Results link on the build pages (standard, green, red), once failures
73	//are encountered, this is set to failed
74	protected String testResultsStatus = "successful";
75	//assume tests ran.  If no html files are found, this is set to false
76	private boolean testsRan = true;
77
78	// Parameters
79	// build runs JUnit automated tests
80	private boolean isBuildTested;
81
82	// buildType, I, N
83	public String buildType;
84
85	// Comma separated list of drop tokens
86	public String dropTokenList;
87
88	// Token in platform.php.template to be replaced by the desired platform ID
89	public String platformIdentifierToken;
90
91	// Location of the xml files
92	public String xmlDirectoryName;
93
94	// Location of the html files
95	public String htmlDirectoryName;
96
97	// Location of the resulting index.php file.
98	public String dropDirectoryName;
99
100	// Location and name of the template index.php file.
101	public String testResultsTemplateFileName;
102
103	// Platform specific template and output list (colon separated) in the following format:
104	// <descriptor, ie. OS name>,path to template file, path to output file
105	public String platformSpecificTemplateList="";
106
107	// Location and name of the template drop index.php file.
108	public String dropTemplateFileName;
109
110	// Name of the generated index php file.
111	public String testResultsHtmlFileName;
112
113	// Name of the generated drop index php file;
114	public String dropHtmlFileName;
115
116	// Arbitrary path used in the index.php page to href the
117	// generated .html files.
118	public String hrefTestResultsTargetPath;
119
120	// Aritrary path used in the index.php page to reference the compileLogs
121	public String hrefCompileLogsTargetPath;
122
123	// Location of compile logs base directory
124	public String compileLogsDirectoryName;
125
126	// Location and name of test manifest file
127	public String testManifestFileName;
128
129	//Initialize the prefix to a default string
130	private String prefix = "default";
131	private String testShortName = "";
132	private int counter = 0;
133	//The four configurations, add new configurations to test results here + update
134	//testResults.php.template for changes
135	private String[] testsConfig = {"linux.gtk.x86.xml",
136			"linux.gtk.x86_6.0.xml",
137			"macosx.cocoa.x86_5.0.xml",
138			"win32.win32.x86.xml",
139			"win32.win32.x86_6.0.xml"};
140
141
142	public static void main(String[] args) {
143		TestResultsGenerator test = new TestResultsGenerator();
144		test.setDropTokenList(
145			"%sdk%,%tests%,%example%,%rcpruntime%,%rcpsdk%,%deltapack%,%icubase%,%runtime%,%platformsdk%,%jdt%,%jdtsdk%,%pde%,%pdesdk%,%cvs%,%cvssdk%,%teamextras%,%swt%,%relengtools%");
146		test.setPlatformIdentifierToken("%platform%");
147		test.getDropTokensFromList(test.dropTokenList);
148		test.setIsBuildTested(true);
149		test.setXmlDirectoryName("C:\\junk\\testresults\\xml");
150		test.setHtmlDirectoryName("C:\\junk\\testresults");
151		test.setDropDirectoryName("C:\\junk");
152		test.setTestResultsTemplateFileName(
153			"C:\\junk\\templateFiles\\testResults.php.template");
154		test.setPlatformSpecificTemplateList(
155				"Windows,C:\\junk\\templateFiles\\platform.php.template,winPlatform.php;Linux,C:\\junk\\templateFiles\\platform.php.template,linPlatform.php;Solaris,C:\\junk\\templateFiles\\platform.php.template,solPlatform.php;AIX,C:\\junk\\templateFiles\\platform.php.template,aixPlatform.php;Macintosh,C:\\junk\\templateFiles\\platform.php.template,macPlatform.php;Source Build,C:\\junk\\templateFiles\\sourceBuilds.php.template,sourceBuilds.php");
156		test.setDropTemplateFileName(
157			"C:\\junk\\templateFiles\\index.php.template");
158		test.setTestResultsHtmlFileName("testResults.php");
159		//test.setDropHtmlFileName("index.php");
160		test.setDropHtmlFileName("index.html");
161
162		test.setHrefTestResultsTargetPath("testresults");
163		test.setCompileLogsDirectoryName(
164			"C:\\junk\\compilelogs\\plugins");
165		test.setHrefCompileLogsTargetPath("compilelogs");
166		test.setTestManifestFileName("C:\\junk\\testManifest.xml");
167		test.execute();
168	}
169
170	public void execute() {
171
172		anErrorTracker = new ErrorTracker();
173		platformDescription = new Vector();
174		platformTemplateString = new Vector();
175		platformDropFileName = new Vector();
176		anErrorTracker.loadFile(testManifestFileName);
177		getDropTokensFromList(dropTokenList);
178		testResultsTemplateString = readFile(testResultsTemplateFileName);
179		dropTemplateString = readFile(dropTemplateFileName);
180
181		//Specific to the platform build-page
182		if(platformSpecificTemplateList!="") {
183			String description, platformTemplateFile, platformDropFile;
184			//Retrieve the different platforms and their info
185			getDifferentPlatformsFromList(platformSpecificTemplateList);
186			//Parses the platform info and retrieves the platform name,
187			//template file, and drop file
188			for(int i=0; i<differentPlatforms.size(); i++) {
189				getPlatformSpecsFromList(differentPlatforms.get(i).toString());
190				description = platformSpecs.get(0).toString();
191				platformTemplateFile = platformSpecs.get(1).toString();
192				platformDropFile = platformSpecs.get(2).toString();
193				platformDescription.add(description);
194				platformTemplateString.add(readFile(platformTemplateFile));
195				platformDropFileName.add(platformDropFile);
196
197			}
198
199		}
200
201		System.out.println("Begin: Generating test results index page");
202		System.out.println("Parsing XML files");
203		parseXml();
204		System.out.println("Parsing compile logs");
205		parseCompileLogs();
206		System.out.println("End: Generating test results index page");
207		writeTestResultsFile();
208		//For the platform build-page, write platform files, in addition to the index file
209		if(platformSpecificTemplateList!="") {
210			writeDropFiles();
211		}
212		else {
213			writeDropIndexFile();
214		}
215	}
216
217	public void parseCompileLogs() {
218
219		StringBuffer compilerString = new StringBuffer();
220		StringBuffer accessesString = new StringBuffer();
221		processCompileLogsDirectory(
222			compileLogsDirectoryName,
223			compilerString,
224			accessesString);
225		if (compilerString.length() == 0) {
226			compilerString.append("None");
227		}
228		if (accessesString.length() == 0) {
229			accessesString.append("None");
230		}
231		testResultsTemplateString =
232			replace(testResultsTemplateString, compileLogsToken, String.valueOf(compilerString));
233
234		testResultsTemplateString =
235			replace(testResultsTemplateString, accessesLogsToken, String.valueOf(accessesString));
236	}
237
238	private void processCompileLogsDirectory(String directoryName, StringBuffer compilerLog, StringBuffer accessesLog) {
239		File sourceDirectory = new File(directoryName);
240		if (sourceDirectory.isFile()) {
241			if (sourceDirectory.getName().endsWith(".log"))
242				readCompileLog(sourceDirectory.getAbsolutePath(), compilerLog, accessesLog);
243			if (sourceDirectory.getName().endsWith(".xml"))
244				parseCompileLog(sourceDirectory.getAbsolutePath(), compilerLog, accessesLog);
245		}
246		if (sourceDirectory.isDirectory()) {
247			File[] logFiles = sourceDirectory.listFiles();
248			Arrays.sort(logFiles);
249			for (int j = 0; j < logFiles.length; j++) {
250				processCompileLogsDirectory(logFiles[j].getAbsolutePath(), compilerLog, accessesLog);
251			}
252		}
253	}
254
255	private void readCompileLog(String log, StringBuffer compilerLog, StringBuffer accessesLog) {
256		String fileContents = readFile(log);
257
258		int errorCount = countCompileErrors(fileContents);
259		int warningCount = countCompileWarnings(fileContents);
260		int forbiddenWarningCount = countForbiddenWarnings(fileContents);
261		int discouragedWarningCount = countDiscouragedWarnings(fileContents);
262		if (errorCount != 0) {
263			//use wildcard in place of version number on directory names
264			String logName =
265				log.substring(getCompileLogsDirectoryName().length() + 1);
266			StringBuffer stringBuffer = new StringBuffer(logName);
267			stringBuffer.replace(
268				logName.indexOf("_") + 1,
269				logName.indexOf(File.separator, logName.indexOf("_") + 1),
270				"*");
271			logName = new String(stringBuffer);
272
273			anErrorTracker.registerError(logName);
274		}
275		formatCompileErrorRow(log, errorCount, warningCount, compilerLog);
276		formatAccessesErrorRow(log, forbiddenWarningCount, discouragedWarningCount, accessesLog);
277	}
278
279	private void parseCompileLog(String log, StringBuffer compilerLog, StringBuffer accessesLog) {
280		int errorCount = 0;
281		int warningCount = 0;
282		int forbiddenWarningCount = 0;
283		int discouragedWarningCount = 0;
284
285		File file=new File(log);
286		Document aDocument=null;
287		BufferedReader reader = null;
288		try {
289			reader = new BufferedReader(new FileReader(file));
290			InputSource inputSource = new InputSource(reader);
291			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
292			DocumentBuilder builder = factory.newDocumentBuilder();
293			aDocument = builder.parse(inputSource);
294		} catch (SAXException e) {
295			e.printStackTrace();
296		} catch (IOException e) {
297			e.printStackTrace();
298		} catch (ParserConfigurationException e) {
299			e.printStackTrace();
300		} finally {
301			if (reader != null) {
302				try {
303					reader.close();
304				} catch(IOException e) {
305					// ignore
306				}
307			}
308		}
309
310		if (aDocument == null) return;
311		// Get summary of problems
312		NodeList nodeList = aDocument.getElementsByTagName("problem");
313		if (nodeList == null ||nodeList.getLength()==0)
314			return;
315
316		int length = nodeList.getLength();
317		for (int i = 0; i < length; i++) {
318			Node problemNode = nodeList.item(i);
319			NamedNodeMap aNamedNodeMap = problemNode.getAttributes();
320			Node severityNode = aNamedNodeMap.getNamedItem("severity");
321			Node idNode = aNamedNodeMap.getNamedItem("id");
322			if (severityNode != null) {
323				String severityNodeValue = severityNode.getNodeValue();
324				if (WARNING_SEVERITY.equals(severityNodeValue)) {
325					// this is a warning
326					// need to check the id
327					String nodeValue = idNode.getNodeValue();
328					if (ForbiddenReferenceID.equals(nodeValue)) {
329						forbiddenWarningCount++;
330					} else if (DiscouragedReferenceID.equals(nodeValue)) {
331						discouragedWarningCount++;
332					} else {
333						warningCount++;
334					}
335				} else if (ERROR_SEVERITY.equals(severityNodeValue)) {
336					// this is an error
337					errorCount++;
338				}
339			}
340		}
341		if (errorCount != 0) {
342			//use wildcard in place of version number on directory names
343			//System.out.println(log + "/n");
344			String logName =
345				log.substring(getCompileLogsDirectoryName().length() + 1);
346			StringBuffer buffer = new StringBuffer(logName);
347			buffer.replace(
348				logName.indexOf("_") + 1,
349				logName.indexOf(File.separator, logName.indexOf("_") + 1),
350				"*");
351			logName = new String(buffer);
352
353			anErrorTracker.registerError(logName);
354		}
355		String logName = log.replaceAll(".xml", ".html");
356		formatCompileErrorRow(
357				logName,
358				errorCount,
359				warningCount,
360				compilerLog);
361		formatAccessesErrorRow(
362				logName,
363				forbiddenWarningCount,
364				discouragedWarningCount,
365				accessesLog);
366	}
367
368	public static byte[] getFileByteContent(String fileName) throws IOException {
369		InputStream stream = null;
370		try {
371			File file = new File(fileName);
372			stream = new FileInputStream(file);
373			return getInputStreamAsByteArray(stream, (int) file.length());
374		} finally {
375			if (stream != null) {
376				try {
377					stream.close();
378				} catch (IOException e) {
379					// ignore
380				}
381			}
382		}
383	}
384
385	/**
386	 * Returns the given input stream's contents as a byte array.
387	 * If a length is specified (ie. if length != -1), only length bytes
388	 * are returned. Otherwise all bytes in the stream are returned.
389	 * Note this doesn't close the stream.
390	 * @throws IOException if a problem occured reading the stream.
391	 */
392	public static byte[] getInputStreamAsByteArray(InputStream stream, int length)
393		throws IOException {
394		byte[] contents;
395		if (length == -1) {
396			contents = new byte[0];
397			int contentsLength = 0;
398			int amountRead = -1;
399			do {
400				int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE);  // read at least 8K
401
402				// resize contents if needed
403				if (contentsLength + amountRequested > contents.length) {
404					System.arraycopy(
405						contents,
406						0,
407						contents = new byte[contentsLength + amountRequested],
408						0,
409						contentsLength);
410				}
411
412				// read as many bytes as possible
413				amountRead = stream.read(contents, contentsLength, amountRequested);
414
415				if (amountRead > 0) {
416					// remember length of contents
417					contentsLength += amountRead;
418				}
419			} while (amountRead != -1);
420
421			// resize contents if necessary
422			if (contentsLength < contents.length) {
423				System.arraycopy(
424					contents,
425					0,
426					contents = new byte[contentsLength],
427					0,
428					contentsLength);
429			}
430		} else {
431			contents = new byte[length];
432			int len = 0;
433			int readSize = 0;
434			while ((readSize != -1) && (len != length)) {
435				// See PR 1FMS89U
436				// We record first the read size. In this case len is the actual read size.
437				len += readSize;
438				readSize = stream.read(contents, len, length - len);
439			}
440		}
441
442		return contents;
443	}
444
445	public String readFile(String fileName) {
446		byte[] aByteArray = null;
447		try {
448			aByteArray = getFileByteContent(fileName);
449		} catch (IOException e) {
450			e.printStackTrace();
451		}
452		if (aByteArray == null) {
453			return "";
454		}
455		return new String(aByteArray);
456	}
457
458	private int countCompileErrors(String aString) {
459		return extractNumber(aString, "error");
460	}
461
462	private int countCompileWarnings(String aString) {
463		return extractNumber(aString, "warning");
464	}
465
466	private int countForbiddenWarnings(String aString) {
467		return extractNumber(aString, "Access restriction:");
468	}
469
470	private int countDiscouragedWarnings(String aString) {
471		return extractNumber(aString, "Discouraged access:");
472	}
473
474	private int extractNumber(String aString, String endToken) {
475		int endIndex = aString.lastIndexOf(endToken);
476		if (endIndex == -1) {
477			return 0;
478		}
479
480		int startIndex = endIndex;
481		while (startIndex >= 0
482			&& aString.charAt(startIndex) != '('
483			&& aString.charAt(startIndex) != ',') {
484			startIndex--;
485		}
486
487		String count = aString.substring(startIndex + 1, endIndex).trim();
488		try {
489			return Integer.parseInt(count);
490		} catch (NumberFormatException e) {
491			return 0;
492		}
493
494	}
495
496	private int missingCount = 0;
497	private String verifyAllTestsRan(String directory) {
498		Enumeration enumeration = (anErrorTracker.getTestLogs()).elements();
499
500		String replaceString="";
501		while (enumeration.hasMoreElements()) {
502			String testLogName = enumeration.nextElement().toString();
503
504			if (new File(directory + File.separator + testLogName)
505				.exists())
506				continue;
507
508			anErrorTracker.registerError(testLogName);
509			String tmp=((platformSpecificTemplateList.equals(""))?formatRow(testLogName, -1, false):formatRowReleng(testLogName, -1, false));
510			if(missingCount==0) {
511				replaceString=replaceString+"</table></br>"+"\n"+
512				"<table width=\"65%\" border=\"1\" bgcolor=\"#EEEEEE\" rules=\"groups\" align=\"center\">"+
513				"<tr bgcolor=\"#9999CC\"> <th width=\"80%\" align=\"center\"> Missing Files </th><th  align=\"center\"> Status </th></tr>";
514			}
515			replaceString=replaceString+tmp;
516			testResultsWithProblems=testResultsWithProblems.concat("\n" + testLogName.substring(0,testLogName.length()-4) +" (file missing)");
517			missingCount++;
518		}
519		return replaceString;
520	}
521
522	public void parseXml() {
523
524		File sourceDirectory = new File(xmlDirectoryName);
525
526		if (sourceDirectory.exists()) {
527
528			String replaceString = "";
529
530			File[] xmlFileNames = sourceDirectory.listFiles();
531			Arrays.sort(xmlFileNames)	;
532
533			File sourceDirectoryParent = sourceDirectory.getParentFile();
534			if (sourceDirectoryParent != null) {
535				sourceDirectoryParent = sourceDirectoryParent.getParentFile();
536			}
537			String sourceDirectoryCanonicalPath = null;
538			try {
539				sourceDirectoryCanonicalPath = sourceDirectoryParent.getCanonicalPath();
540			} catch (IOException e) {
541				// ignore
542			}
543			for (int i = 0; i < xmlFileNames.length; i++) {
544				if (xmlFileNames[i].getPath().endsWith(".xml")) {
545					String fullName = xmlFileNames[i].getPath();
546					int errorCount = countErrors(fullName);
547					if (errorCount != 0) {
548						String testName =
549							xmlFileNames[i].getName().substring(
550								0,
551								xmlFileNames[i].getName().length() - 4);
552						testResultsWithProblems =
553							testResultsWithProblems.concat("\n" + testName);
554						testResultsXmlUrls =
555							testResultsXmlUrls.concat("\n" + extractXmlRelativeFileName(sourceDirectoryCanonicalPath, xmlFileNames[i]));
556						anErrorTracker.registerError(
557							fullName.substring(
558								getXmlDirectoryName().length() + 1));
559					}
560
561
562					String tmp=((platformSpecificTemplateList.equals(""))?formatRow(xmlFileNames[i].getPath(), errorCount,true):formatRowReleng(xmlFileNames[i].getPath(), errorCount,true));
563					replaceString=replaceString+tmp;
564
565
566				}
567			}
568			//check for missing test logs
569			replaceString=replaceString+verifyAllTestsRan(xmlDirectoryName);
570
571			testResultsTemplateString =
572				replace(
573					testResultsTemplateString,
574					testResultsToken,
575					replaceString);
576			testsRan = true;
577
578		} else {
579			testsRan = false;
580			System.out.println(
581				"Test results not found in "
582					+ sourceDirectory.getAbsolutePath());
583		}
584
585	}
586	private static String extractXmlRelativeFileName(String rootCanonicalPath, File xmlFile) {
587		if (rootCanonicalPath != null) {
588			String xmlFileCanonicalPath = null;
589			try {
590				xmlFileCanonicalPath = xmlFile.getCanonicalPath();
591			} catch (IOException e) {
592				// ignore
593			}
594			if (xmlFileCanonicalPath != null) {
595				// + 1 to remove the '\'
596				return xmlFileCanonicalPath.substring(rootCanonicalPath.length() + 1).replace('\\', '/');
597			}
598		}
599		return "";
600	}
601	private String replace(
602		String source,
603		String original,
604		String replacement) {
605
606		int replaceIndex = source.indexOf(original);
607		if (replaceIndex > -1) {
608			String resultString = source.substring(0, replaceIndex);
609			resultString = resultString + replacement;
610			resultString =
611				resultString
612					+ source.substring(replaceIndex + original.length());
613			return resultString;
614		} else {
615			System.out.println("Could not find token: " + original);
616			return source;
617		}
618
619	}
620
621	protected void writeDropFiles() {
622		writeDropIndexFile();
623		//Write all the platform files
624		for(int i=0; i<platformDescription.size(); i++) {
625			writePlatformFile(platformDescription.get(i).toString(), platformTemplateString.get(i).toString(), platformDropFileName.get(i).toString());
626		}
627	}
628
629	protected void writeDropIndexFile() {
630
631		String[] types = anErrorTracker.getTypes();
632		for (int i = 0; i < types.length; i++) {
633			PlatformStatus[] platforms = anErrorTracker.getPlatforms(types[i]);
634			String replaceString = processDropRows(platforms);
635			dropTemplateString =
636				replace(
637					dropTemplateString,
638					dropTokens.get(i).toString(),
639					replaceString);
640			}
641		//Replace the token %testsStatus% with the status of the test results
642		dropTemplateString = replace(dropTemplateString,"%testsStatus%",testResultsStatus);
643		String outputFileName =
644			dropDirectoryName + File.separator + dropHtmlFileName;
645		writeFile(outputFileName, dropTemplateString);
646	}
647
648	//Writes the platform file (dropFileName) specific to "desiredPlatform"
649	protected void writePlatformFile(String desiredPlatform, String templateString, String dropFileName) {
650
651		String[] types = anErrorTracker.getTypes();
652		for (int i = 0; i < types.length; i++) {
653			PlatformStatus[] platforms = anErrorTracker.getPlatforms(types[i]);
654			//Call processPlatformDropRows passing the platform's name
655			String replaceString = processPlatformDropRows(platforms, desiredPlatform);
656			templateString =
657				replace(
658					templateString,
659					dropTokens.get(i).toString(),
660					replaceString);
661		}
662		//Replace the platformIdentifierToken with the platform's name and the testsStatus
663		//token with the status of the test results
664		templateString = replace(templateString, platformIdentifierToken, desiredPlatform);
665		templateString = replace(templateString,"%testsStatus%",testResultsStatus);
666		String outputFileName =
667			dropDirectoryName + File.separator + dropFileName;
668		writeFile(outputFileName, templateString);
669	}
670
671	//Process drop rows specific to each of the platforms
672	protected String processPlatformDropRows(PlatformStatus[] platforms, String name) {
673
674		String result = "";
675		boolean found = false;
676		for (int i = 0; i < platforms.length; i++) {
677			//If the platform description indicates the platform's name, or "All",
678			//call processDropRow
679			if(platforms[i].getName().startsWith(name.substring(0, 3)) || platforms[i].getName().equals("All")) {
680				result = result + processDropRow(platforms[i]);
681				found = true;
682			}
683			//If the platform description indicates "All Other Platforms", process
684			//the row locally
685			else if(platforms[i].getName().equals("All Other Platforms") && !found)
686			{
687				String imageName = "";
688
689				if (platforms[i].hasErrors()) {
690					imageName =
691						"<a href=\"" + getTestResultsHtmlFileName() + "\"><img src = \"FAIL.gif\" width=19 height=23></a>";
692				} else {
693					if (testsRan) {
694						imageName = "<img src = \"OK.gif\" width=19 height=23>";
695					} else {
696						if (isBuildTested) {
697							imageName =
698								"<font size=\"-1\" color=\"#FF0000\">pending</font>";
699						} else {
700							imageName = "<img src = \"OK.gif\" width=19 height=23>";
701						}
702					}
703				}
704
705				result = result + "<tr>";
706				result = result + "<td><div align=left>" + imageName + "</div></td>\n";
707				result = result + "<td>All " + name + "</td>";
708				//generate http, md5 and sha1 links by calling php functions in the template
709				result = result + "<td><?php genLinks($_SERVER[\"SERVER_NAME\"],\"@buildlabel@\",\"" + platforms[i].getFileName() +"\"); ?></td>\n";
710				result = result + "</tr>\n";
711			}
712		}
713
714		return result;
715	}
716
717	protected String processDropRows(PlatformStatus[] platforms) {
718
719		String result = "";
720		for (int i = 0; i < platforms.length; i++) {
721			result = result + processDropRow(platforms[i]);
722		}
723
724		return result;
725	}
726
727	protected String processDropRow(PlatformStatus aPlatform) {
728
729		String imageName = "";
730
731		if (aPlatform.hasErrors()) {
732			imageName =
733				"<a href=\"" + getTestResultsHtmlFileName()+ "\"><img src = \"FAIL.gif\" width=19 height=23></a>";
734			//Failure in tests
735			testResultsStatus = "failed";
736		} else {
737			if (testsRan) {
738				imageName = "<img src = \"OK.gif\" width=19 height=23>";
739			} else {
740				if (isBuildTested) {
741					imageName =
742						"<font size=\"-1\" color=\"#FF0000\">pending</font>";
743					//Tests are pending
744					testResultsStatus = "pending";
745				} else {
746					imageName = "<img src = \"OK.gif\" width=19 height=23>";
747				}
748			}
749		}
750
751		String result = "<tr>";
752
753		result = result + "<td><div align=left>" + imageName + "</div></td>\n";
754		result = result + "<td>" + aPlatform.getName() + "</td>";
755		result = result + "<td>" + aPlatform.getFileName() + "</td>\n";
756		result = result + "</tr>\n";
757
758		return result;
759	}
760
761	public void writeTestResultsFile() {
762
763		String outputFileName =
764			dropDirectoryName + File.separator + testResultsHtmlFileName;
765		writeFile(outputFileName, testResultsTemplateString);
766	}
767
768	private void writeFile(String outputFileName, String contents) {
769		FileOutputStream outputStream = null;
770		try {
771			outputStream = new FileOutputStream(outputFileName);
772			outputStream.write(contents.getBytes());
773		} catch (FileNotFoundException e) {
774			System.out.println(
775				"File not found exception writing: " + outputFileName);
776		} catch (IOException e) {
777			System.out.println("IOException writing: " + outputFileName);
778		} finally {
779			if (outputStream != null) {
780				try {
781					outputStream.close();
782				} catch(IOException e) {
783					// ignore
784				}
785			}
786		}
787	}
788
789	public void setTestResultsHtmlFileName(String aString) {
790		testResultsHtmlFileName = aString;
791	}
792
793	public String getTestResultsHtmlFileName() {
794		return testResultsHtmlFileName;
795	}
796
797	public void setTestResultsTemplateFileName(String aString) {
798		testResultsTemplateFileName = aString;
799	}
800
801	public String getTestResultsTemplateFileName() {
802		return testResultsTemplateFileName;
803	}
804
805	public void setXmlDirectoryName(String aString) {
806		xmlDirectoryName = aString;
807	}
808
809	public String getXmlDirectoryName() {
810		return xmlDirectoryName;
811	}
812
813	public void setHtmlDirectoryName(String aString) {
814		htmlDirectoryName = aString;
815	}
816
817	public String getHtmlDirectoryName() {
818		return htmlDirectoryName;
819	}
820
821	public void setDropDirectoryName(String aString) {
822		dropDirectoryName = aString;
823	}
824
825	public String getDropDirectoryName() {
826		return dropDirectoryName;
827	}
828
829	private void formatCompileErrorRow(
830		String fileName,
831		int errorCount,
832		int warningCount,
833		StringBuffer buffer) {
834
835		if (errorCount == 0 && warningCount == 0) {
836			return;
837		}
838
839		String hrefCompileLogsTargetPath2 = getHrefCompileLogsTargetPath();
840		int i = fileName.indexOf(hrefCompileLogsTargetPath2);
841
842		String shortName =
843			fileName.substring(i + hrefCompileLogsTargetPath2.length());
844
845		buffer
846			.append("<tr>\n<td>\n")
847			.append("<a href=")
848			.append("\"")
849			.append(hrefCompileLogsTargetPath2)
850			.append(shortName)
851			.append("\">")
852			.append(shortName)
853			.append("</a>")
854			.append("</td>\n")
855			.append("<td align=\"center\">")
856			.append("<a href=")
857			.append("\"")
858			.append(hrefCompileLogsTargetPath2)
859			.append(shortName)
860			.append("#ERRORS")
861			.append("\">")
862			.append(errorCount)
863			.append("</a>")
864			.append("</td>\n")
865			.append("<td align=\"center\">")
866			.append("<a href=")
867			.append("\"")
868			.append(hrefCompileLogsTargetPath2)
869			.append(shortName)
870			.append("#OTHER_WARNINGS")
871			.append("\">")
872			.append(warningCount)
873			.append("</a>")
874			.append("</td>\n")
875			.append("</tr>\n");
876	}
877
878	private void formatAccessesErrorRow(
879			String fileName,
880			int forbiddenAccessesWarningsCount,
881			int discouragedAccessesWarningsCount,
882			StringBuffer buffer) {
883
884		if (forbiddenAccessesWarningsCount == 0 && discouragedAccessesWarningsCount == 0) {
885			return;
886		}
887
888		String hrefCompileLogsTargetPath2 = getHrefCompileLogsTargetPath();
889		int i = fileName.indexOf(hrefCompileLogsTargetPath2);
890
891		String shortName =
892			fileName.substring(i + hrefCompileLogsTargetPath2.length());
893
894		buffer
895			.append("<tr>\n<td>\n")
896			.append("<a href=")
897			.append("\"")
898			.append(hrefCompileLogsTargetPath2)
899			.append(shortName)
900			.append("\">")
901			.append(shortName)
902			.append("</a>")
903			.append("</td>\n")
904			.append("<td align=\"center\">")
905			.append("<a href=")
906			.append("\"")
907			.append(hrefCompileLogsTargetPath2)
908			.append(shortName)
909			.append("#FORBIDDEN_WARNINGS")
910			.append("\">")
911			.append(forbiddenAccessesWarningsCount)
912			.append("</a>")
913			.append("</td>\n")
914			.append("<td align=\"center\">")
915			.append("<a href=")
916			.append("\"")
917			.append(hrefCompileLogsTargetPath2)
918			.append(shortName)
919			.append("#DISCOURAGED_WARNINGS")
920			.append("\">")
921			.append(discouragedAccessesWarningsCount)
922			.append("</a>")
923			.append("</td>\n")
924			.append("</tr>\n");
925		}
926
927	private String formatRow(String fileName, int errorCount, boolean link) {
928
929		// replace .xml with .html
930
931		String aString = "";
932		if (!link) {
933			return "<tr><td>" + fileName + " (missing)" + "</td><td>" + "DNF";
934		}
935
936		if (fileName.endsWith(".xml")) {
937
938			int begin = fileName.lastIndexOf(File.separatorChar);
939			int end = fileName.lastIndexOf(".xml");
940
941			String shortName = fileName.substring(begin + 1, end);
942			String displayName = shortName;
943			if (errorCount != 0)
944			   aString = aString + "<tr><td><b>";
945			else
946				aString = aString + "<tr><td>";
947
948
949			if (errorCount!=0){
950				displayName="<font color=\"#ff0000\">"+displayName+"</font>";
951			}
952			if (errorCount==-1){
953				aString=aString.concat(displayName);
954			}else {
955				aString=aString
956					+ "<a href="
957					+ "\""
958					+ hrefTestResultsTargetPath
959					+ "/"
960					+ shortName
961					+ ".html"
962					+ "\">"
963					+ displayName
964					+ "</a>";
965			}
966			if (errorCount > 0)
967				   aString = aString + "</td><td><b>";
968			else
969				aString = aString + "</td><td>";
970
971			if (errorCount == -1)
972				aString = aString + "<font color=\"#ff0000\">DNF";
973
974			else if (errorCount >0)
975				aString = aString + "<font color=\"#ff0000\">"+String.valueOf(errorCount);
976			else
977				aString = aString +String.valueOf(errorCount);
978
979			if (errorCount != 0)
980				aString = aString + "</font></b></td></tr>";
981			else
982				aString = aString + "</td></tr>";
983		}
984
985		return aString;
986
987	}
988
989	//Specific to the RelEng test results page
990	private String formatRowReleng(String fileName, int errorCount, boolean link) {
991
992		//If the file name doesn't end with any of the set test configurations, do nothing
993		boolean endsWithConfig = false;
994		int card = testsConfig.length;
995		for(int i=0; i<card; i++) {
996			if(fileName.endsWith(testsConfig[i]))
997				endsWithConfig = true;
998		}
999		if(!endsWithConfig)
1000			return "";
1001
1002		String aString = "";
1003		if (!link) {
1004			return "<tr><td>" + fileName + "</td><td align=\"center\">" + "DNF </tr>";
1005		}
1006
1007		if (fileName.endsWith(".xml")) {
1008
1009			int begin = fileName.lastIndexOf(File.separatorChar);
1010
1011			//Get org.eclipse. out of the component name
1012			String shortName = fileName.substring(begin + 13, fileName.indexOf('_'));
1013			String displayName = shortName;
1014
1015			//If the short name does not start with this prefix
1016			if(!shortName.startsWith(prefix)) {
1017				//If the prefix is not yet set
1018				if(prefix=="default"){
1019					//Set the testShortName variable to the current short name
1020					testShortName = shortName;
1021					counter=0;
1022					//Set new prefix
1023					prefix = shortName.substring(0, shortName.indexOf(".tests") + 6);
1024					aString = aString + "<tbody><tr><td><b>" + prefix + ".*" + "</b><td><td><td><td>";
1025					aString = aString + "<tr><td><P>" + shortName;
1026
1027					//Loop until the matching string postfix(test config.) is found
1028					while(counter<card && !fileName.endsWith(testsConfig[counter])) {
1029						aString = aString + "<td align=\"center\">-</td>";
1030						counter++;
1031					}
1032				}
1033				else {
1034					//Set new prefix
1035					prefix = shortName.substring(0, shortName.indexOf(".tests") + 6);
1036
1037					//Loop until the matching string postfix(test config.) is found
1038					while(counter<card && !fileName.endsWith(testsConfig[counter])) {
1039						aString = aString + "<td align=\"center\">-</td>";
1040						counter++;
1041					}
1042
1043					//In this case, the new prefix should be set with the short name under it,
1044					//since this would mean that the team has more than one component test
1045					if(!shortName.endsWith("tests")) {
1046						aString = aString + "<tbody><tr><td><b>" + prefix + ".*" + "</b><td><td><td><td>";
1047						aString = aString + "<tr><td><P>" + shortName;
1048					}
1049					//The team has only one component test
1050					else
1051						aString = aString + "<tbody><tr><td><b>" + shortName;
1052					testShortName = shortName;
1053
1054					counter = 0;
1055				}
1056			}
1057			//If the file's short name starts with the current prefix
1058			if(shortName.startsWith(prefix)) {
1059				//If the new file has a different short name than the current one
1060				if(!shortName.equals(testShortName)){
1061					//Fill the remaining cells with '-'. These files will later be listed as
1062					//missing
1063					while(counter<card) {
1064						aString = aString + "<td align=\"center\">-</td>";
1065						counter++;
1066					}
1067					counter = 0;
1068					//Print the component name
1069					aString = aString + "<tr><td><P>" + shortName;
1070					//Loop until the matching string postfix(test config.) is found
1071					while(counter<card && !fileName.endsWith(testsConfig[counter])) {
1072						aString = aString + "<td align=\"center\">-</td>";
1073						counter++;
1074					}
1075				}
1076				else {
1077					//Loop until the matching string postfix(test config.) is found
1078					while(counter<card && !fileName.endsWith(testsConfig[counter])) {
1079						aString = aString + "<td align=\"center\">-</td>";
1080						counter++;
1081					}
1082					//If the previous component has no more test files left
1083					if(counter==card) {
1084						counter = 0;
1085						//Print the new component name
1086						aString = aString + "<tr><td><P>" + shortName;
1087						//Loop until the matching string postfix(test config.) is found
1088						while(counter<card && !fileName.endsWith(testsConfig[counter])) {
1089							aString = aString + "<td align=\"center\">-</td>";
1090							counter++;
1091						}
1092					}
1093				}
1094
1095				testShortName = shortName;
1096
1097				if (errorCount != 0)
1098					aString = aString + "<td align=\"center\"><b>";
1099				else
1100					aString = aString + "<td align=\"center\">";
1101
1102				//Print number of errors
1103				if (errorCount!=0){
1104					displayName="<font color=\"#ff0000\">"+ "(" + String.valueOf(errorCount) + ")" +"</font>";
1105				}
1106				else {
1107					displayName="(0)";
1108				}
1109
1110				//Reference
1111				if (errorCount==-1){
1112					aString=aString.concat(displayName);
1113				}else {
1114					aString=aString
1115						+ "<a href="
1116						+ "\""
1117						+ hrefTestResultsTargetPath
1118						+ "/"
1119						+ fileName.substring(begin+1, fileName.length()-4)
1120						+ ".html"
1121						+ "\">"
1122						+ displayName
1123						+ "</a>";
1124				}
1125
1126				if (errorCount == -1)
1127					aString = aString + "<font color=\"#ff0000\">DNF";
1128
1129				if (errorCount != 0)
1130					aString = aString + "</font></b></td>";
1131				else
1132					aString = aString + "</td>";
1133				counter++;
1134			}
1135		}
1136
1137		return aString;
1138	}
1139
1140	private int countErrors(String fileName) {
1141		int errorCount = 0;
1142
1143		if (new File(fileName).length()==0)
1144			return -1;
1145
1146		try {
1147			DocumentBuilderFactory docBuilderFactory=DocumentBuilderFactory.newInstance();
1148			parser=docBuilderFactory.newDocumentBuilder();
1149
1150			Document document = parser.parse(fileName);
1151			NodeList elements = document.getElementsByTagName(elementName);
1152
1153			int elementCount = elements.getLength();
1154			if (elementCount == 0)
1155				return -1;
1156			for (int i = 0; i < elementCount; i++) {
1157				Element element = (Element) elements.item(i);
1158				NamedNodeMap attributes = element.getAttributes();
1159				Node aNode = attributes.getNamedItem("errors");
1160				errorCount =
1161					errorCount + Integer.parseInt(aNode.getNodeValue());
1162				aNode = attributes.getNamedItem("failures");
1163				errorCount =
1164					errorCount + Integer.parseInt(aNode.getNodeValue());
1165
1166			}
1167
1168		} catch (IOException e) {
1169			System.out.println("IOException: " + fileName);
1170			// e.printStackTrace();
1171			return 0;
1172		} catch (SAXException e) {
1173			System.out.println("SAXException: " + fileName);
1174			// e.printStackTrace();
1175			return 0;
1176		} catch (ParserConfigurationException e) {
1177			e.printStackTrace();
1178		}
1179		return errorCount;
1180	}
1181
1182
1183
1184	/**
1185	 * Gets the hrefTestResultsTargetPath.
1186	 * @return Returns a String
1187	 */
1188	public String getHrefTestResultsTargetPath() {
1189		return hrefTestResultsTargetPath;
1190	}
1191
1192	/**
1193	 * Sets the hrefTestResultsTargetPath.
1194	 * @param hrefTestResultsTargetPath The hrefTestResultsTargetPath to set
1195	 */
1196	public void setHrefTestResultsTargetPath(String htmlTargetPath) {
1197		this.hrefTestResultsTargetPath = htmlTargetPath;
1198	}
1199
1200	/**
1201	 * Gets the compileLogsDirectoryName.
1202	 * @return Returns a String
1203	 */
1204	public String getCompileLogsDirectoryName() {
1205		return compileLogsDirectoryName;
1206	}
1207
1208	/**
1209	 * Sets the compileLogsDirectoryName.
1210	 * @param compileLogsDirectoryName The compileLogsDirectoryName to set
1211	 */
1212	public void setCompileLogsDirectoryName(String compileLogsDirectoryName) {
1213		this.compileLogsDirectoryName = compileLogsDirectoryName;
1214	}
1215
1216	/**
1217	 * Gets the hrefCompileLogsTargetPath.
1218	 * @return Returns a String
1219	 */
1220	public String getHrefCompileLogsTargetPath() {
1221		return hrefCompileLogsTargetPath;
1222	}
1223
1224	/**
1225	 * Sets the hrefCompileLogsTargetPath.
1226	 * @param hrefCompileLogsTargetPath The hrefCompileLogsTargetPath to set
1227	 */
1228	public void setHrefCompileLogsTargetPath(String hrefCompileLogsTargetPath) {
1229		this.hrefCompileLogsTargetPath = hrefCompileLogsTargetPath;
1230	}
1231
1232	/**
1233	 * Gets the testManifestFileName.
1234	 * @return Returns a String
1235	 */
1236	public String getTestManifestFileName() {
1237		return testManifestFileName;
1238	}
1239
1240	/**
1241	 * Sets the testManifestFileName.
1242	 * @param testManifestFileName The testManifestFileName to set
1243	 */
1244	public void setTestManifestFileName(String testManifestFileName) {
1245		this.testManifestFileName = testManifestFileName;
1246	}
1247
1248	/**
1249	 * Gets the dropHtmlFileName.
1250	 * @return Returns a String
1251	 */
1252	public String getDropHtmlFileName() {
1253		return dropHtmlFileName;
1254	}
1255
1256	/**
1257	 * Sets the dropHtmlFileName.
1258	 * @param dropHtmlFileName The dropHtmlFileName to set
1259	 */
1260	public void setDropHtmlFileName(String dropHtmlFileName) {
1261		this.dropHtmlFileName = dropHtmlFileName;
1262	}
1263
1264	/**
1265	 * Gets the dropTemplateFileName.
1266	 * @return Returns a String
1267	 */
1268	public String getDropTemplateFileName() {
1269		return dropTemplateFileName;
1270	}
1271
1272	/**
1273	 * Sets the dropTemplateFileName.
1274	 * @param dropTemplateFileName The dropTemplateFileName to set
1275	 */
1276	public void setDropTemplateFileName(String dropTemplateFileName) {
1277		this.dropTemplateFileName = dropTemplateFileName;
1278	}
1279
1280	protected void getDropTokensFromList(String list) {
1281		StringTokenizer tokenizer = new StringTokenizer(list, ",");
1282		dropTokens = new Vector();
1283
1284		while (tokenizer.hasMoreTokens()) {
1285			dropTokens.add(tokenizer.nextToken());
1286		}
1287	}
1288
1289	protected void getDifferentPlatformsFromList(String list) {
1290		StringTokenizer tokenizer = new StringTokenizer(list, ";");
1291		differentPlatforms = new Vector();
1292
1293		while (tokenizer.hasMoreTokens()) {
1294			differentPlatforms.add(tokenizer.nextToken());
1295		}
1296	}
1297
1298	protected void getPlatformSpecsFromList(String list) {
1299		StringTokenizer tokenizer = new StringTokenizer(list, ",");
1300		platformSpecs = new Vector();
1301
1302		while (tokenizer.hasMoreTokens()) {
1303			platformSpecs.add(tokenizer.nextToken());
1304		}
1305	}
1306
1307	public String getDropTokenList() {
1308		return dropTokenList;
1309	}
1310
1311	public void setDropTokenList(String dropTokenList) {
1312		this.dropTokenList = dropTokenList;
1313	}
1314
1315	public boolean isBuildTested() {
1316		return isBuildTested;
1317	}
1318
1319	public void setIsBuildTested(boolean isBuildTested) {
1320		this.isBuildTested = isBuildTested;
1321	}
1322
1323
1324	/**
1325	 * @return
1326	 */
1327	public boolean testsRan() {
1328		return testsRan;
1329	}
1330
1331	/**
1332	 * @param b
1333	 */
1334	public void setTestsRan(boolean b) {
1335		testsRan = b;
1336	}
1337
1338	/**
1339	 * @return
1340	 */
1341	public Vector getDropTokens() {
1342		return dropTokens;
1343	}
1344
1345	/**
1346	 * @param vector
1347	 */
1348	public void setDropTokens(Vector vector) {
1349		dropTokens = vector;
1350	}
1351
1352	/**
1353	 * @return
1354	 */
1355	public String getTestResultsWithProblems() {
1356		return testResultsWithProblems;
1357	}
1358
1359	/**
1360	 * @return
1361	 */
1362	public String getTestResultsXmlUrls() {
1363		return testResultsXmlUrls;
1364	}
1365
1366	/**
1367	 * @param string
1368	 */
1369	public void setTestResultsWithProblems(String string) {
1370		testResultsWithProblems = string;
1371	}
1372
1373	public String getBuildType() {
1374		return buildType;
1375	}
1376
1377	public void setBuildType(String buildType) {
1378		this.buildType = buildType;
1379	}
1380
1381	public String getPlatformSpecificTemplateList() {
1382		return platformSpecificTemplateList;
1383	}
1384
1385	public void setPlatformSpecificTemplateList(String platformSpecificTemplateList) {
1386		this.platformSpecificTemplateList = platformSpecificTemplateList;
1387	}
1388
1389	public void setPlatformIdentifierToken(String platformIdentifierToken) {
1390		this.platformIdentifierToken = platformIdentifierToken;
1391	}
1392
1393	public String getPlatformIdentifierToken() {
1394		return platformIdentifierToken;
1395	}
1396
1397}
1398