001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.util.table;
028
029
030
031 import java.io.BufferedWriter;
032 import java.io.OutputStream;
033 import java.io.OutputStreamWriter;
034 import java.io.PrintWriter;
035 import java.io.Writer;
036
037
038
039 /**
040 * An interface for creating a CSV formatted table.
041 */
042 public final class CSVTablePrinter extends TablePrinter {
043
044 /**
045 * Table serializer implementation.
046 */
047 private final class Serializer extends TableSerializer {
048
049 // The current column being output.
050 private int column = 0;
051
052 // Counts the number of separators that should be output the next
053 // time a non-empty cell is displayed. The comma separators are
054 // not displayed immediately so that we can avoid displaying
055 // unnecessary trailing separators.
056 private int requiredSeparators = 0;
057
058
059
060 // Private constructor.
061 private Serializer() {
062 // No implementation required.
063 }
064
065
066
067 /**
068 * {@inheritDoc}
069 */
070 @Override
071 public void addCell(String s) {
072 // Avoid printing comma separators for trailing empty cells.
073 if (s.length() == 0) {
074 requiredSeparators++;
075 } else {
076 for (int i = 0; i < requiredSeparators; i++) {
077 writer.print(',');
078 }
079 requiredSeparators = 1;
080 }
081
082 boolean needsQuoting = false;
083
084 if (s.contains(",")) {
085 needsQuoting = true;
086 }
087
088 if (s.contains("\n")) {
089 needsQuoting = true;
090 }
091
092 if (s.contains("\r")) {
093 needsQuoting = true;
094 }
095
096 if (s.contains("\"")) {
097 needsQuoting = true;
098 s = s.replace("\"", "\"\"");
099 }
100
101 if (s.startsWith(" ")) {
102 needsQuoting = true;
103 }
104
105 if (s.endsWith(" ")) {
106 needsQuoting = true;
107 }
108
109 StringBuilder builder = new StringBuilder();
110 if (needsQuoting) {
111 builder.append("\"");
112 }
113
114 builder.append(s);
115
116 if (needsQuoting) {
117 builder.append("\"");
118 }
119
120 writer.print(builder.toString());
121 column++;
122 }
123
124
125
126 /**
127 * {@inheritDoc}
128 */
129 @Override
130 public void addHeading(String s) {
131 if (displayHeadings) {
132 addCell(s);
133 }
134 }
135
136
137
138 /**
139 * {@inheritDoc}
140 */
141 @Override
142 public void endHeader() {
143 if (displayHeadings) {
144 writer.println();
145 }
146 }
147
148
149
150 /**
151 * {@inheritDoc}
152 */
153 @Override
154 public void endRow() {
155 writer.println();
156 }
157
158
159
160 /**
161 * {@inheritDoc}
162 */
163 @Override
164 public void endTable() {
165 writer.flush();
166 }
167
168
169
170 /**
171 * {@inheritDoc}
172 */
173 @Override
174 public void startHeader() {
175 column = 0;
176 requiredSeparators = 0;
177 }
178
179
180
181 /**
182 * {@inheritDoc}
183 */
184 @Override
185 public void startRow() {
186 column = 0;
187 requiredSeparators = 0;
188 }
189 }
190
191 // Indicates whether or not the headings should be output.
192 private boolean displayHeadings = false;
193
194 // The output destination.
195 private PrintWriter writer = null;
196
197
198
199 /**
200 * Creates a new CSV table printer for the specified output stream.
201 * Headings will not be displayed by default.
202 *
203 * @param stream
204 * The stream to output tables to.
205 */
206 public CSVTablePrinter(OutputStream stream) {
207 this(new BufferedWriter(new OutputStreamWriter(stream)));
208 }
209
210
211
212 /**
213 * Creates a new CSV table printer for the specified writer.
214 * Headings will not be displayed by default.
215 *
216 * @param writer
217 * The writer to output tables to.
218 */
219 public CSVTablePrinter(Writer writer) {
220 this.writer = new PrintWriter(writer);
221 }
222
223
224
225 /**
226 * Specify whether or not table headings should be displayed.
227 *
228 * @param displayHeadings
229 * <code>true</code> if table headings should be
230 * displayed.
231 */
232 public void setDisplayHeadings(boolean displayHeadings) {
233 this.displayHeadings = displayHeadings;
234 }
235
236
237
238 /**
239 * {@inheritDoc}
240 */
241 @Override
242 protected TableSerializer getSerializer() {
243 return new Serializer();
244 }
245
246 }