001/* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2013 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * SonarQube is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.utils.text; 021 022import javax.annotation.Nullable; 023import javax.xml.stream.XMLOutputFactory; 024import javax.xml.stream.XMLStreamException; 025import javax.xml.stream.XMLStreamWriter; 026import java.io.Writer; 027 028/** 029 * TODO document that output is UTF-8 030 */ 031public class XmlWriter { 032 033 public static XmlWriter of(Writer writer) { 034 return new XmlWriter(writer); 035 } 036 037 private final XMLStreamWriter stream; 038 039 private XmlWriter(Writer writer) { 040 try { 041 XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); 042 stream = xmlFactory.createXMLStreamWriter(writer); 043 } catch (Exception e) { 044 throw new WriterException("Fail to initialize XML Stream writer", e); 045 } 046 } 047 048 public XmlWriter declaration() { 049 try { 050 stream.writeStartDocument(); 051 return this; 052 } catch (XMLStreamException e) { 053 throw rethrow(e); 054 } 055 } 056 057 public XmlWriter begin(String nodeName) { 058 try { 059 stream.writeStartElement(nodeName); 060 return this; 061 } catch (XMLStreamException e) { 062 throw rethrow(e); 063 } 064 } 065 066 067 public XmlWriter end() { 068 try { 069 stream.writeEndElement(); 070 return this; 071 } catch (XMLStreamException e) { 072 throw rethrow(e); 073 } 074 } 075 076 public XmlWriter prop(String nodeName, @Nullable String value) { 077 if (value != null) { 078 begin(nodeName).value(value).end(); 079 } 080 return this; 081 } 082 083 public XmlWriter prop(String nodeName, @Nullable Number value) { 084 if (value != null) { 085 begin(nodeName).value(value).end(); 086 } 087 return this; 088 } 089 090 public XmlWriter prop(String nodeName, boolean value) { 091 return begin(nodeName).value(value).end(); 092 } 093 094 public XmlWriter prop(String nodeName, long value) { 095 return begin(nodeName).value(value).end(); 096 } 097 098 public XmlWriter prop(String nodeName, double value) { 099 return begin(nodeName).value(value).end(); 100 } 101 102 private XmlWriter value(boolean value) { 103 try { 104 stream.writeCharacters(String.valueOf(value)); 105 return this; 106 } catch (XMLStreamException e) { 107 throw rethrow(e); 108 } 109 } 110 111 private XmlWriter value(double value) { 112 try { 113 if (Double.isNaN(value) || Double.isInfinite(value)) { 114 throw new WriterException("Fail to write XML. Double value is not valid: " + value); 115 } 116 stream.writeCharacters(String.valueOf(value)); 117 return this; 118 } catch (XMLStreamException e) { 119 throw rethrow(e); 120 } 121 } 122 123 private XmlWriter value(@Nullable String value) { 124 try { 125 if (value != null) { 126 stream.writeCharacters(value); 127 } 128 return this; 129 } catch (XMLStreamException e) { 130 throw rethrow(e); 131 } 132 } 133 134 private XmlWriter value(long value) { 135 try { 136 stream.writeCharacters(String.valueOf(value)); 137 return this; 138 } catch (XMLStreamException e) { 139 throw rethrow(e); 140 } 141 } 142 143 private XmlWriter value(@Nullable Number value) { 144 try { 145 if (value != null) { 146 stream.writeCharacters(String.valueOf(value)); 147 } 148 return this; 149 } catch (XMLStreamException e) { 150 throw rethrow(e); 151 } 152 } 153 154 public void close() { 155 try { 156 stream.writeEndDocument(); 157 stream.flush(); 158 stream.close(); 159 } catch (XMLStreamException e) { 160 throw rethrow(e); 161 } 162 } 163 164 private IllegalStateException rethrow(XMLStreamException e) { 165 // stacktrace is not helpful 166 throw new IllegalStateException("Fail to write XML: " + e.getMessage()); 167 } 168}