001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
005: * Contact: sequoia@continuent.org
006: *
007: * Licensed under the Apache License, Version 2.0 (the "License");
008: * you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: *
019: * Initial developer(s): Jeff Mesnil.
020: * Contributor(s): ______________________.
021: */package org.continuent.sequoia.console.text.formatter;
022:
023: import java.sql.ResultSet;
024: import java.sql.ResultSetMetaData;
025: import java.sql.SQLException;
026: import java.util.ArrayList;
027: import java.util.List;
028:
029: import org.continuent.sequoia.common.i18n.ConsoleTranslate;
030: import org.continuent.sequoia.console.text.Console;
031: import org.continuent.sequoia.console.text.ConsoleException;
032:
033: /**
034: * Utility class to format a <code>ResultSet</code> to display it prettily in
035: * the text console
036: *
037: * @author <a href="mailto:jeff.mesnil@emicnetworks.com">Jeff Mesnil</a>
038: */
039: public class ResultSetFormatter {
040:
041: /**
042: * by default, display result set's rows horizontally (everything on the same line)
043: */
044: private static boolean displayRowsHorizontally = true;
045:
046: /** Max column width when displaying a <code>ResultSet</code>. */
047: private static final int MAX_COLUMN_DISPLAY_WIDTH = 25;
048:
049: /**
050: * Toggles the display of rows either horizontally (by default) or vertically.
051: *
052: * @return <code>true</code> if the result set's rows will be displayed
053: * horizontally (everything on the same line), <code>false</code> if
054: * the rows will be displayed vertically (one row cell per line, one
055: * row after the other)
056: */
057: public static boolean toggleRowDisplay() {
058: displayRowsHorizontally = !displayRowsHorizontally;
059: return displayRowsHorizontally;
060: }
061:
062: public static void display(ResultSet rs, int fetchsize,
063: Console console) {
064: int totalLines = 0;
065: String[] headers = getHeaders(rs);
066: List cells;
067: do {
068: cells = getCells(rs, fetchsize);
069: if (cells.size() == 0) {
070: return;
071: }
072: totalLines += cells.size();
073: String[][] matrix = (String[][]) cells
074: .toArray(new String[cells.size()][]);
075: String out = TableFormatter.format(headers, matrix,
076: displayRowsHorizontally);
077: console.println(out);
078: if (fetchsize != 0 && cells.size() % fetchsize == 0) {
079: try {
080: console.readLine(ConsoleTranslate.get(
081: "sql.display.next.rows", new Integer[] {
082: new Integer(fetchsize),
083: new Integer(totalLines) }));
084: } catch (ConsoleException e) {
085: }
086: }
087: } while (cells != null && cells.size() > 0);
088: }
089:
090: private static List getCells(ResultSet rs, int fetchsize) {
091: try {
092: ResultSetMetaData meta = rs.getMetaData();
093: int columnCount = meta.getColumnCount();
094: List cells = new ArrayList();
095: while (rs.next()) {
096: String[] cell = new String[columnCount];
097: for (int j = 0; j < columnCount; j++) {
098: String object = rs.getString(j + 1);
099: String value = (object != null) ? object : "";
100: cell[j] = value;
101: }
102: cells.add(cell);
103: if (fetchsize != 0 && (cells.size() % fetchsize == 0)) {
104: return cells;
105: }
106: }
107: return cells;
108: } catch (SQLException e) {
109: return null;
110: }
111: }
112:
113: private static String[] getHeaders(ResultSet rs) {
114: try {
115: ResultSetMetaData meta = rs.getMetaData();
116: int columnCount = meta.getColumnCount();
117: String[] headers = new String[columnCount];
118: meta = rs.getMetaData();
119: for (int i = 0; i < columnCount; i++) {
120: headers[i] = meta.getColumnName(i + 1);
121: }
122: return headers;
123: } catch (SQLException e) {
124: return new String[0];
125: }
126: }
127:
128: /**
129: * Format and display the given <code>ResultSet</code> on the console.
130: *
131: * @param rs the <code>ResultSet</code> to display
132: * @param fetchsize fetchisze value
133: * @param console console where the ResultSet will be displayed and he size of
134: * the result set)
135: * @throws SQLException if an error occurs
136: */
137: public static void formatAndDisplay(ResultSet rs, int fetchsize,
138: Console console) throws SQLException {
139: // Get the metadata
140: ResultSetMetaData meta = rs.getMetaData();
141: int columnCount = meta.getColumnCount();
142:
143: console.println();
144:
145: appendSeparatorLine(columnCount, meta, console);
146:
147: // Print the column names
148: console.print("|");
149: for (int i = 1; i <= columnCount; i++) {
150: console.print(" ");
151: // Pad the column name and print it
152: int size = meta.getColumnDisplaySize(i);
153: String columnName = meta.getColumnName(i);
154: if (size <= 0) {
155: if (columnName != null)
156: size = columnName.length();
157: else
158: size = 0;
159: }
160: appendPad(columnName, size, console);
161: console.print(" |");
162: }
163: console.println();
164:
165: appendSeparatorLine(columnCount, meta, console);
166:
167: // Display the results
168: String object;
169: int line = 0;
170: while (rs.next()) {
171: console.print("|");
172: for (int i = 1; i <= columnCount; i++) {
173: console.print(" ");
174: String value = null;
175: try {
176: object = rs.getString(i);
177: value = (object != null) ? object : "";
178: } catch (SQLException e) {
179: value = e.getMessage();
180: }
181:
182: // Pad the value and print it
183: int size = meta.getColumnDisplaySize(i);
184: if (size <= 0) {
185: if (value != null)
186: size = value.length();
187: else
188: size = 0;
189: }
190: appendPad(value, size, console);
191: console.print(" |");
192: }
193: console.println();
194: line++;
195: if (fetchsize != 0) {
196: if (line % fetchsize == 0) {
197: try {
198: console.readLine(ConsoleTranslate.get(
199: "sql.display.next.rows", new Integer[] {
200: new Integer(fetchsize),
201: new Integer(line) }));
202: } catch (ConsoleException ignore) {
203: }
204: }
205: }
206: }
207:
208: appendSeparatorLine(columnCount, meta, console);
209: }
210:
211: private static void appendSeparatorLine(int columnCount,
212: ResultSetMetaData meta, Console console)
213: throws SQLException {
214:
215: console.print("+");
216: for (int i = 1; i <= columnCount; i++) {
217: int size = meta.getColumnDisplaySize(i);
218: if (size > MAX_COLUMN_DISPLAY_WIDTH)
219: size = MAX_COLUMN_DISPLAY_WIDTH;
220: console.print("-");
221: for (int j = 0; j < size; j++)
222: console.print("-");
223: console.print("-+");
224: }
225: console.println();
226: }
227:
228: private static void appendPad(String text, int size, Console console) {
229: if (size > MAX_COLUMN_DISPLAY_WIDTH)
230: size = MAX_COLUMN_DISPLAY_WIDTH;
231: if (size < text.length()) {
232: console.print(text.substring(0, size - 1) + "~");
233: return;
234: }
235: StringBuffer toPad = new StringBuffer(size);
236: toPad.insert(0, text);
237: while (toPad.length() < size)
238: toPad.append(' ');
239: console.print(toPad.toString());
240: }
241: }
|