# HG changeset patch # User František Kučera # Date 1387573266 -3600 # Node ID 37fe883f8410687a283b7d240d1444d806c7c3c6 # Parent d42ed0d10a10ca755dec48c0825e4c4799898665 formatter: interface and abstract class diff -r d42ed0d10a10 -r 37fe883f8410 java/sql-dk/src/info/globalcode/sql/dk/formatting/AbstractFormatter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/AbstractFormatter.java Fri Dec 20 22:01:06 2013 +0100 @@ -0,0 +1,241 @@ +/** + * SQL-DK + * Copyright © 2013 František Kučera (frantovo.cz) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package info.globalcode.sql.dk.formatting; + +import info.globalcode.sql.dk.Parameter; +import java.io.OutputStream; +import java.util.EmptyStackException; +import java.util.EnumSet; +import java.util.List; +import java.util.Stack; + +/** + * + * @author Ing. František Kučera (frantovo.cz) + */ +public abstract class AbstractFormatter implements Formatter { + + private Stack state = new Stack<>(); + private OutputStream outputStream; + private ColumnsHeader currentColumnsHeader; + private String currentQuery; + private int currentColumnsCount; + + public AbstractFormatter(OutputStream outputStream) { + this.outputStream = outputStream; + state.push(State.ROOT); + } + + /* + * root + * .database + * ..resultSet + * ...@query + * ...@parameters + * ...@columnsHeader + * ...row + * ....@columnValue + * ..updatesResult + * ...@query + * ...@parameters + * ...@updatedRowsCount + * ...generatedKeys + * ....resultSet (see above) + */ + protected enum State { + + ROOT, + DATABASE, + RESULT_SET, + ROW, + UPDATES_RESULT, + GENERATED_KEYS + } + + /** + * Go down in hierarchy. + * Pushes new state and verifies the old one. + * + * @param current the new state – currently entering + * @param expected expected previous states (any of them is valid) + * @return previous state + * @throws IllegalStateException if previous state was not one from expected + */ + private State pushState(State current, EnumSet expected) { + State previous = state.peek(); + + if (expected.contains(previous)) { + state.push(current); + return previous; + } else { + throw new IllegalStateException("Formatter was in wrong state: " + previous + " when it should be in one of: " + expected); + } + } + + protected State peekState(EnumSet expected) { + State current = state.peek(); + + if (expected.contains(current)) { + return current; + } else { + throw new IllegalStateException("Formatter is in wrong state: " + current + " when it should be in one of: " + expected); + } + + } + + /** + * Go up in hierarchy. + * Pops the superior state/branch. + * + * @param expected expected superior state + * @return the superior state + * @throws IllegalStateException if superior state was not one from expected or if there is no + * more superior state (we are at root level) + */ + private State popState(EnumSet expected) { + try { + State superior = state.pop(); + if (expected.contains(superior)) { + return superior; + } else { + throw new IllegalStateException("Formatter had wrong superior state: " + superior + " when it should be in one of: " + expected); + } + } catch (EmptyStackException e) { + throw new IllegalStateException("Formatter was already at root level – there is nothing above that.", e); + } + } + + @Override + public void writeStartDatabase() { + pushState(State.DATABASE, EnumSet.of(State.ROOT)); + } + + @Override + public void writeEndDatabase() { + popState(EnumSet.of(State.ROOT)); + } + + @Override + public void writeStartResultSet() { + pushState(State.RESULT_SET, EnumSet.of(State.DATABASE, State.GENERATED_KEYS)); + } + + @Override + public void writeEndResultSet() { + popState(EnumSet.of(State.DATABASE, State.GENERATED_KEYS)); + currentColumnsHeader = null; + } + + @Override + public void writeQuery(String sql) { + peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT)); + + if (currentColumnsHeader == null) { + currentQuery = sql; + } else { + throw new IllegalStateException("Query string '" + sql + "' must be set before columns header – was already set: " + currentColumnsHeader); + } + } + + @Override + public void writeParameters(List parameters) { + peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT)); + + if (currentColumnsHeader != null) { + throw new IllegalStateException("Parameters '" + parameters + "' must be set before columns header – was already set: " + currentColumnsHeader); + } + + if (currentQuery == null) { + throw new IllegalStateException("Parameters '" + parameters + "' must be set after query – was not yet set."); + } + } + + @Override + public void writeColumnsHeader(ColumnsHeader header) { + peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT)); + + if (currentColumnsHeader == null) { + currentColumnsHeader = header; + } else { + throw new IllegalStateException("Columns header can be set only once per result set – was already set: " + currentColumnsHeader); + } + } + + @Override + public void writeStartRow() { + pushState(State.ROW, EnumSet.of(State.RESULT_SET)); + currentColumnsCount = 0; + } + + @Override + public void writeEndRow() { + popState(EnumSet.of(State.RESULT_SET)); + } + + @Override + public void writeColumnValue(Object value) { + peekState(EnumSet.of(State.ROW)); + currentColumnsCount++; + + int declaredCount = currentColumnsHeader.getColumnCount(); + if (currentColumnsCount > declaredCount) { + throw new IllegalStateException("Current columns count is " + currentColumnsCount + " which is more than declared " + declaredCount + " in header."); + } + } + + @Override + public void writeStartUpdatesResult() { + pushState(State.RESULT_SET, EnumSet.of(State.DATABASE)); + } + + @Override + public void writeEndUpdatesResult() { + popState(EnumSet.of(State.DATABASE)); + currentColumnsHeader = null; + } + + @Override + public void writeUpdatedRowsCount(int updatedRowsCount) { + peekState(EnumSet.of(State.UPDATES_RESULT)); + } + + @Override + public void writeStartGeneratedKeys() { + pushState(State.GENERATED_KEYS, EnumSet.of(State.UPDATES_RESULT)); + } + + @Override + public void writeEndGeneratedKeys() { + popState(EnumSet.of(State.UPDATES_RESULT)); + } + + protected OutputStream getOutputStream() { + return outputStream; + } + + protected ColumnsHeader getCurrentColumnsHeader() { + return currentColumnsHeader; + } + + protected int getCurrentColumnsCount() { + return currentColumnsCount; + } + /** + * TODO: write SQLWarning + */ +} diff -r d42ed0d10a10 -r 37fe883f8410 java/sql-dk/src/info/globalcode/sql/dk/formatting/ColumnsHeader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/ColumnsHeader.java Fri Dec 20 22:01:06 2013 +0100 @@ -0,0 +1,35 @@ +/** + * SQL-DK + * Copyright © 2013 František Kučera (frantovo.cz) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package info.globalcode.sql.dk.formatting; + +/** + * + * @author Ing. František Kučera (frantovo.cz) + */ +public class ColumnsHeader { + + public int getColumnCount() { + /** + * TODO: getColumnCount + */ + throw new RuntimeException("Not yet implemented"); + } + /** + * TODO: columns descriptor + */ +} diff -r d42ed0d10a10 -r 37fe883f8410 java/sql-dk/src/info/globalcode/sql/dk/formatting/Formatter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/Formatter.java Fri Dec 20 22:01:06 2013 +0100 @@ -0,0 +1,58 @@ +/** + * SQL-DK + * Copyright © 2013 František Kučera (frantovo.cz) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package info.globalcode.sql.dk.formatting; + +import info.globalcode.sql.dk.Parameter; +import java.util.List; + +/** + * + * @author Ing. František Kučera (frantovo.cz) + */ +public interface Formatter { + + void writeStartDatabase(); + + void writeEndDatabase(); + + void writeStartResultSet(); + + void writeEndResultSet(); + + void writeQuery(String sql); + + void writeParameters(List parameters); + + void writeColumnsHeader(ColumnsHeader header); + + void writeStartRow(); + + void writeColumnValue(Object value); + + void writeEndRow(); + + void writeStartUpdatesResult(); + + void writeUpdatedRowsCount(int updatedRowsCount); + + void writeStartGeneratedKeys(); + + void writeEndGeneratedKeys(); + + void writeEndUpdatesResult(); +}