001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 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 */
020 package org.sonar.api.utils.text;
021
022 import javax.annotation.Nullable;
023 import javax.xml.stream.XMLOutputFactory;
024 import javax.xml.stream.XMLStreamException;
025 import javax.xml.stream.XMLStreamWriter;
026 import java.io.Writer;
027
028 /**
029 * TODO document that output is UTF-8
030 */
031 public class XmlWriter {
032
033 private final XMLStreamWriter stream;
034
035 private XmlWriter(Writer writer) {
036 try {
037 XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
038 stream = xmlFactory.createXMLStreamWriter(writer);
039 } catch (Exception e) {
040 throw new WriterException("Fail to initialize XML Stream writer", e);
041 }
042 }
043
044 public static XmlWriter of(Writer writer) {
045 return new XmlWriter(writer);
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 }