3 * Copyright © 2013 František Kučera (frantovo.cz)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package info.globalcode.sql.dk.formatting;
20 import info.globalcode.sql.dk.Parameter;
21 import java.util.EmptyStackException;
22 import java.util.EnumSet;
23 import java.util.List;
24 import java.util.Stack;
28 * @author Ing. František Kučera (frantovo.cz)
30 public abstract class AbstractFormatter implements Formatter {
32 private Stack<State> state = new Stack<>();
33 private FormatterContext formatterContext;
34 private ColumnsHeader currentColumnsHeader;
35 private String currentQuery;
36 private int currentColumnsCount;
38 public AbstractFormatter(FormatterContext formatterContext) {
39 this.formatterContext = formatterContext;
40 state.push(State.ROOT);
55 * ...@updatedRowsCount
57 * ....resultSet (see above)
59 protected enum State {
70 * Go down in hierarchy.
71 * Pushes new state and verifies the old one.
73 * @param current the new state – currently entering
74 * @param expected expected previous states (any of them is valid)
75 * @return previous state
76 * @throws IllegalStateException if previous state was not one from expected
78 private State pushState(State current, EnumSet expected) {
79 State previous = state.peek();
81 if (expected.contains(previous)) {
85 throw new IllegalStateException("Formatter was in wrong state: " + previous + " when it should be in one of: " + expected);
89 protected State peekState(EnumSet expected) {
90 State current = state.peek();
92 if (expected.contains(current)) {
95 throw new IllegalStateException("Formatter is in wrong state: " + current + " when it should be in one of: " + expected);
101 * Go up in hierarchy.
102 * Pops the superior state/branch.
104 * @param expected expected superior state
105 * @return the superior state
106 * @throws IllegalStateException if superior state was not one from expected or if there is no
107 * more superior state (we are at root level)
109 private State popState(EnumSet expected) {
111 State superior = state.pop();
112 if (expected.contains(superior)) {
115 throw new IllegalStateException("Formatter had wrong superior state: " + superior + " when it should be in one of: " + expected);
117 } catch (EmptyStackException e) {
118 throw new IllegalStateException("Formatter was already at root level – there is nothing above that.", e);
123 public void writeStartDatabase() {
124 pushState(State.DATABASE, EnumSet.of(State.ROOT));
128 public void writeEndDatabase() {
129 popState(EnumSet.of(State.ROOT));
133 public void writeStartResultSet() {
134 pushState(State.RESULT_SET, EnumSet.of(State.DATABASE, State.GENERATED_KEYS));
138 public void writeEndResultSet() {
139 popState(EnumSet.of(State.DATABASE, State.GENERATED_KEYS));
140 currentColumnsHeader = null;
144 public void writeQuery(String sql) {
145 peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT));
147 if (currentColumnsHeader == null) {
150 throw new IllegalStateException("Query string '" + sql + "' must be set before columns header – was already set: " + currentColumnsHeader);
155 public void writeParameters(List<Parameter> parameters) {
156 peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT));
158 if (currentColumnsHeader != null) {
159 throw new IllegalStateException("Parameters '" + parameters + "' must be set before columns header – was already set: " + currentColumnsHeader);
162 if (currentQuery == null) {
163 throw new IllegalStateException("Parameters '" + parameters + "' must be set after query – was not yet set.");
168 public void writeColumnsHeader(ColumnsHeader header) {
169 peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT));
171 if (currentColumnsHeader == null) {
172 currentColumnsHeader = header;
174 throw new IllegalStateException("Columns header can be set only once per result set – was already set: " + currentColumnsHeader);
179 public void writeStartRow() {
180 pushState(State.ROW, EnumSet.of(State.RESULT_SET));
181 currentColumnsCount = 0;
185 public void writeEndRow() {
186 popState(EnumSet.of(State.RESULT_SET));
190 public void writeColumnValue(Object value) {
191 peekState(EnumSet.of(State.ROW));
192 currentColumnsCount++;
194 int declaredCount = currentColumnsHeader.getColumnCount();
195 if (currentColumnsCount > declaredCount) {
196 throw new IllegalStateException("Current columns count is " + currentColumnsCount + " which is more than declared " + declaredCount + " in header.");
201 public void writeStartUpdatesResult() {
202 pushState(State.RESULT_SET, EnumSet.of(State.DATABASE));
206 public void writeEndUpdatesResult() {
207 popState(EnumSet.of(State.DATABASE));
208 currentColumnsHeader = null;
212 public void writeUpdatedRowsCount(int updatedRowsCount) {
213 peekState(EnumSet.of(State.UPDATES_RESULT));
217 public void writeStartGeneratedKeys() {
218 pushState(State.GENERATED_KEYS, EnumSet.of(State.UPDATES_RESULT));
222 public void writeEndGeneratedKeys() {
223 popState(EnumSet.of(State.UPDATES_RESULT));
226 public FormatterContext getFormatterContext() {
227 return formatterContext;
230 protected ColumnsHeader getCurrentColumnsHeader() {
231 return currentColumnsHeader;
234 protected int getCurrentColumnsCount() {
235 return currentColumnsCount;
238 * TODO: write SQLWarning