1 /* 2 * $Id$ 3 * 4 * Copyright (c) 2006, 2011, 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.mrep; 28 29 import java.io.BufferedWriter; 30 import java.io.File; 31 import java.io.FileOutputStream; 32 import java.io.IOException; 33 import java.io.OutputStreamWriter; 34 import java.io.Writer; 35 import java.text.DateFormat; 36 import java.text.ParseException; 37 import java.text.SimpleDateFormat; 38 import java.util.Date; 39 import java.util.Map; 40 import java.util.Properties; 41 import javax.xml.parsers.ParserConfigurationException; 42 import org.xml.sax.Attributes; 43 import org.xml.sax.ContentHandler; 44 import org.xml.sax.SAXException; 45 import org.xml.sax.ext.LexicalHandler; 46 import org.xml.sax.helpers.AttributesImpl; 47 import org.xml.sax.helpers.DefaultHandler; 48 import com.sun.javatest.report.XMLReportMaker; 49 import javax.xml.transform.TransformerConfigurationException; 50 import javax.xml.transform.TransformerFactory; 51 import javax.xml.transform.sax.SAXTransformerFactory; 52 import javax.xml.transform.sax.TransformerHandler; 53 import javax.xml.transform.stream.StreamResult; 54 import org.xml.sax.InputSource; 55 import org.xml.sax.XMLReader; 56 57 58 59 class XMLReportWriter { 60 public static String XML_CHARSET = "UTF-8"; 61 private final AttributesImpl emptyAttr = new AttributesImpl(); 62 private TransformerHandler ser; 63 64 private Writer fw; 65 66 public XMLReportWriter(File file) throws IOException{ 67 Properties outputProps = new Properties(); 68 outputProps.put("indent", "yes"); 69 70 outputProps.put("encoding", XML_CHARSET); 71 72 SAXTransformerFactory stf = (SAXTransformerFactory )TransformerFactory.newInstance(); 73 stf.setAttribute("indent-number", 4); 74 try { 75 ser = stf.newTransformerHandler(); 76 } catch (TransformerConfigurationException ex) { 77 ex.printStackTrace(); 78 } 79 80 ser.getTransformer().setOutputProperties(outputProps); 81 82 fw = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(file), XMLReportMaker.XML_CHARSET)); 83 ser.setResult(new StreamResult(fw)); 84 } 85 86 /** 87 * Convert date to string in ISO-8601 or xs:dateTime format 88 * 89 * @param date 90 * Date 91 * @return ISO-8601 String 92 */ 93 static String dateToISO8601(Date date) { 94 DateFormat dfISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); 95 // format in (almost) ISO8601 format 96 String dateStr = dfISO8601.format(date); 97 // remap the timezone from 0000 to 00:00 (starts at char 22) 98 return dateStr.substring(0, 22) + ":" + dateStr.substring(22); 99 } 100 101 /** 102 * Convert string in ISO-8601 or xs:dateTime format to date 103 * 104 * @param dateStr 105 * ISO-8601 String 106 * @return corresponding date 107 */ 108 static Date ISO8601toDate(String dateStr) throws ParseException { 109 DateFormat dfISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); 110 // format in (almost) ISO8601 format 111 Date date = dfISO8601.parse(dateStr.substring(0, 22) 112 + dateStr.substring(23)); 113 // remap the timezone from 0000 to 00:00 (starts at char 22) 114 return date; 115 } 116 117 private void sReport() throws SAXException { 118 AttributesImpl atts = new AttributesImpl(); 119 atts.addAttribute("", "", Scheme.XSI, "String", Scheme.XSI_VAL); 120 atts.addAttribute("", "", Scheme.SCH_LOC, "String", Scheme.SCH_LOC_VAL); 121 atts.addAttribute("", "", Scheme.REPORT_FORMST, "String", "v1"); 122 atts.addAttribute("", "", Scheme.REPORT_GENTIME, "String", 123 dateToISO8601(new Date())); 124 ser.startElement("", "", Scheme.REPORT, atts); 125 } 126 127 public void write(File[] file, Map[] map) throws SAXException, 128 ParserConfigurationException, IOException { 129 try { 130 ser.startDocument(); 131 sReport(); 132 ser.startElement("", "", Scheme.WDS, emptyAttr); 133 for (int i = 0; i < file.length; i++) { 134 XMLReader reader = XMLReportReader.createXMLReader(false); 135 reader.setContentHandler(new CopyHandler(ser, true, map[i])); 136 reader.parse(new InputSource(file[i].getAbsolutePath())); 137 } 138 ser.endElement("", "", Scheme.WDS); 139 ser.startElement("", "", Scheme.TRS, emptyAttr); 140 for (int i = 0; i < file.length; i++) { 141 XMLReader reader = XMLReportReader.createXMLReader(false); 142 reader.setContentHandler(new CopyHandler(ser, false, map[i])); 143 reader.parse(new InputSource(file[i].getAbsolutePath())); 144 } 145 ser.endElement("", "", Scheme.TRS); 146 ser.endElement("", "", Scheme.REPORT); 147 ser.endDocument(); 148 } finally { 149 fw.close(); 150 } 151 152 } 153 } 154 155 // This handler just copy one xml to other, 156 // modifying elements according mapping 157 158 class CopyHandler extends DefaultHandler { 159 160 private ContentHandler ser; 161 private LexicalHandler lh; 162 163 // are we collect workdirs or not 164 private final boolean isWorkDir; 165 166 // is it need to write 167 private boolean needWrite; 168 169 // skipping by conflict resolving 170 private boolean skipByConflict; 171 172 // id -> new_id mapping 173 // url -> new_TestDescr mapping 174 private Map map; 175 176 public CopyHandler(ContentHandler ser, boolean isWorkDir, Map map) { 177 this.ser = ser; 178 if (ser instanceof LexicalHandler) { 179 lh = (LexicalHandler) ser; 180 } 181 this.isWorkDir = isWorkDir; 182 this.needWrite = false; 183 this.map = map; 184 this.skipByConflict = false; 185 } 186 187 public void startElement(String namespaceUri, String localName, 188 String qName, Attributes attrs) throws SAXException { 189 if (needWrite == true && skipByConflict == false) { 190 191 if (qName.equals(Scheme.WD)) { 192 // for WD WD_ID may be updated 193 AttributesImpl newAttrs = new AttributesImpl(); 194 for (int i = 0; i < attrs.getLength(); i++) { 195 if (attrs.getQName(i).equals(Scheme.WD_ID)) { 196 String id = String.valueOf(map.get(Integer 197 .valueOf(attrs.getValue(i)))); 198 newAttrs.addAttribute(attrs.getURI(i), attrs 199 .getLocalName(i), attrs.getQName(i), attrs 200 .getType(i), id); 201 } else { 202 newAttrs.addAttribute(attrs.getURI(i), attrs 203 .getLocalName(i), attrs.getQName(i), attrs 204 .getType(i), attrs.getValue(i)); 205 } 206 } 207 ser.startElement("", "", qName, newAttrs); 208 } else if (qName.equals(Scheme.TR)) { 209 // for TR TR_WDID may be updated 210 // or TR may be skipped during conflic resolving 211 AttributesImpl newAttrs = new AttributesImpl(); 212 for (int i = 0; i < attrs.getLength(); i++) { 213 if (attrs.getQName(i).equals(Scheme.TR_WDID)) { 214 int id = ((TestResultDescr) map.get(attrs 215 .getValue(Scheme.TR_URL))).getID(); 216 if (id < 0) { 217 skipByConflict = true; 218 return; 219 } 220 String idS = String.valueOf(id); 221 newAttrs.addAttribute(attrs.getURI(i), attrs 222 .getLocalName(i), attrs.getQName(i), attrs 223 .getType(i), idS); 224 } else { 225 newAttrs.addAttribute(attrs.getURI(i), attrs 226 .getLocalName(i), attrs.getQName(i), attrs 227 .getType(i), attrs.getValue(i)); 228 } 229 } 230 ser.startElement("", "", qName, newAttrs); 231 } else { 232 // by default source attributes are used 233 ser.startElement("", "", qName, attrs); 234 } 235 236 } 237 238 // don't write TRS, WDS 239 // they are written by XMLReportWriter 240 // also mode needWrite may be changed 241 if (isWorkDir == true && qName.equals(Scheme.WDS)) { 242 needWrite = true; 243 } 244 if (isWorkDir == false && qName.equals(Scheme.TRS)) { 245 needWrite = true; 246 } 247 } 248 249 public void characters(char[] arg0, int arg1, int arg2) throws SAXException { 250 if (this.needWrite == false || this.skipByConflict == true) 251 return; 252 // copy only text is really present 253 if (String.copyValueOf(arg0, arg1, arg2).trim().equals("")) 254 return; 255 lh.startCDATA(); 256 ser.characters(arg0, arg1, arg2); 257 lh.endCDATA(); 258 } 259 260 public void endElement(String arg0, String arg1, String arg2) 261 throws SAXException { 262 // don't write TRS, WDS 263 // they are written by XMLReportWriter 264 // also mode needWrite may be changed 265 if (isWorkDir == true && arg2.equals(Scheme.WDS)) { 266 needWrite = false; 267 } 268 if (isWorkDir == false && arg2.equals(Scheme.TRS)) { 269 needWrite = false; 270 } 271 if (needWrite == true) { 272 if (skipByConflict == false) 273 ser.endElement(arg0, arg1, arg2); 274 else if (arg2.equals(Scheme.TR)) { 275 skipByConflict = false; 276 } 277 } 278 } 279 }