formatter: interface and abstract class v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Fri, 20 Dec 2013 22:01:06 +0100
branchv_0
changeset 2237fe883f8410
parent 21 d42ed0d10a10
child 23 d8faf91519a5
formatter: interface and abstract class
java/sql-dk/src/info/globalcode/sql/dk/formatting/AbstractFormatter.java
java/sql-dk/src/info/globalcode/sql/dk/formatting/ColumnsHeader.java
java/sql-dk/src/info/globalcode/sql/dk/formatting/Formatter.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/AbstractFormatter.java	Fri Dec 20 22:01:06 2013 +0100
     1.3 @@ -0,0 +1,241 @@
     1.4 +/**
     1.5 + * SQL-DK
     1.6 + * Copyright © 2013 František Kučera (frantovo.cz)
     1.7 + *
     1.8 + * This program is free software: you can redistribute it and/or modify
     1.9 + * it under the terms of the GNU General Public License as published by
    1.10 + * the Free Software Foundation, either version 3 of the License, or
    1.11 + * (at your option) any later version.
    1.12 + *
    1.13 + * This program is distributed in the hope that it will be useful,
    1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    1.16 + * GNU General Public License for more details.
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License
    1.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    1.20 + */
    1.21 +package info.globalcode.sql.dk.formatting;
    1.22 +
    1.23 +import info.globalcode.sql.dk.Parameter;
    1.24 +import java.io.OutputStream;
    1.25 +import java.util.EmptyStackException;
    1.26 +import java.util.EnumSet;
    1.27 +import java.util.List;
    1.28 +import java.util.Stack;
    1.29 +
    1.30 +/**
    1.31 + *
    1.32 + * @author Ing. František Kučera (frantovo.cz)
    1.33 + */
    1.34 +public abstract class AbstractFormatter implements Formatter {
    1.35 +
    1.36 +	private Stack<State> state = new Stack<>();
    1.37 +	private OutputStream outputStream;
    1.38 +	private ColumnsHeader currentColumnsHeader;
    1.39 +	private String currentQuery;
    1.40 +	private int currentColumnsCount;
    1.41 +
    1.42 +	public AbstractFormatter(OutputStream outputStream) {
    1.43 +		this.outputStream = outputStream;
    1.44 +		state.push(State.ROOT);
    1.45 +	}
    1.46 +
    1.47 +	/*
    1.48 +	 * root
    1.49 +	 * .database
    1.50 +	 * ..resultSet
    1.51 +	 * ...@query
    1.52 +	 * ...@parameters
    1.53 +	 * ...@columnsHeader
    1.54 +	 * ...row
    1.55 +	 * ....@columnValue
    1.56 +	 * ..updatesResult
    1.57 +	 * ...@query
    1.58 +	 * ...@parameters
    1.59 +	 * ...@updatedRowsCount
    1.60 +	 * ...generatedKeys
    1.61 +	 * ....resultSet (see above)
    1.62 +	 */
    1.63 +	protected enum State {
    1.64 +
    1.65 +		ROOT,
    1.66 +		DATABASE,
    1.67 +		RESULT_SET,
    1.68 +		ROW,
    1.69 +		UPDATES_RESULT,
    1.70 +		GENERATED_KEYS
    1.71 +	}
    1.72 +
    1.73 +	/**
    1.74 +	 * Go down in hierarchy.
    1.75 +	 * Pushes new state and verifies the old one.
    1.76 +	 *
    1.77 +	 * @param current the new state – currently entering
    1.78 +	 * @param expected expected previous states (any of them is valid)
    1.79 +	 * @return previous state
    1.80 +	 * @throws IllegalStateException if previous state was not one from expected
    1.81 +	 */
    1.82 +	private State pushState(State current, EnumSet expected) {
    1.83 +		State previous = state.peek();
    1.84 +
    1.85 +		if (expected.contains(previous)) {
    1.86 +			state.push(current);
    1.87 +			return previous;
    1.88 +		} else {
    1.89 +			throw new IllegalStateException("Formatter was in wrong state: " + previous + " when it should be in one of: " + expected);
    1.90 +		}
    1.91 +	}
    1.92 +
    1.93 +	protected State peekState(EnumSet expected) {
    1.94 +		State current = state.peek();
    1.95 +
    1.96 +		if (expected.contains(current)) {
    1.97 +			return current;
    1.98 +		} else {
    1.99 +			throw new IllegalStateException("Formatter is in wrong state: " + current + " when it should be in one of: " + expected);
   1.100 +		}
   1.101 +
   1.102 +	}
   1.103 +
   1.104 +	/**
   1.105 +	 * Go up in hierarchy.
   1.106 +	 * Pops the superior state/branch.
   1.107 +	 *
   1.108 +	 * @param expected expected superior state
   1.109 +	 * @return the superior state
   1.110 +	 * @throws IllegalStateException if superior state was not one from expected or if there is no
   1.111 +	 * more superior state (we are at root level)
   1.112 +	 */
   1.113 +	private State popState(EnumSet expected) {
   1.114 +		try {
   1.115 +			State superior = state.pop();
   1.116 +			if (expected.contains(superior)) {
   1.117 +				return superior;
   1.118 +			} else {
   1.119 +				throw new IllegalStateException("Formatter had wrong superior state: " + superior + " when it should be in one of: " + expected);
   1.120 +			}
   1.121 +		} catch (EmptyStackException e) {
   1.122 +			throw new IllegalStateException("Formatter was already at root level – there is nothing above that.", e);
   1.123 +		}
   1.124 +	}
   1.125 +
   1.126 +	@Override
   1.127 +	public void writeStartDatabase() {
   1.128 +		pushState(State.DATABASE, EnumSet.of(State.ROOT));
   1.129 +	}
   1.130 +
   1.131 +	@Override
   1.132 +	public void writeEndDatabase() {
   1.133 +		popState(EnumSet.of(State.ROOT));
   1.134 +	}
   1.135 +
   1.136 +	@Override
   1.137 +	public void writeStartResultSet() {
   1.138 +		pushState(State.RESULT_SET, EnumSet.of(State.DATABASE, State.GENERATED_KEYS));
   1.139 +	}
   1.140 +
   1.141 +	@Override
   1.142 +	public void writeEndResultSet() {
   1.143 +		popState(EnumSet.of(State.DATABASE, State.GENERATED_KEYS));
   1.144 +		currentColumnsHeader = null;
   1.145 +	}
   1.146 +
   1.147 +	@Override
   1.148 +	public void writeQuery(String sql) {
   1.149 +		peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT));
   1.150 +
   1.151 +		if (currentColumnsHeader == null) {
   1.152 +			currentQuery = sql;
   1.153 +		} else {
   1.154 +			throw new IllegalStateException("Query string '" + sql + "' must be set before columns header – was already set: " + currentColumnsHeader);
   1.155 +		}
   1.156 +	}
   1.157 +
   1.158 +	@Override
   1.159 +	public void writeParameters(List<Parameter> parameters) {
   1.160 +		peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT));
   1.161 +
   1.162 +		if (currentColumnsHeader != null) {
   1.163 +			throw new IllegalStateException("Parameters '" + parameters + "' must be set before columns header – was already set: " + currentColumnsHeader);
   1.164 +		}
   1.165 +
   1.166 +		if (currentQuery == null) {
   1.167 +			throw new IllegalStateException("Parameters '" + parameters + "' must be set after query – was not yet set.");
   1.168 +		}
   1.169 +	}
   1.170 +
   1.171 +	@Override
   1.172 +	public void writeColumnsHeader(ColumnsHeader header) {
   1.173 +		peekState(EnumSet.of(State.RESULT_SET, State.UPDATES_RESULT));
   1.174 +
   1.175 +		if (currentColumnsHeader == null) {
   1.176 +			currentColumnsHeader = header;
   1.177 +		} else {
   1.178 +			throw new IllegalStateException("Columns header can be set only once per result set – was already set: " + currentColumnsHeader);
   1.179 +		}
   1.180 +	}
   1.181 +
   1.182 +	@Override
   1.183 +	public void writeStartRow() {
   1.184 +		pushState(State.ROW, EnumSet.of(State.RESULT_SET));
   1.185 +		currentColumnsCount = 0;
   1.186 +	}
   1.187 +
   1.188 +	@Override
   1.189 +	public void writeEndRow() {
   1.190 +		popState(EnumSet.of(State.RESULT_SET));
   1.191 +	}
   1.192 +
   1.193 +	@Override
   1.194 +	public void writeColumnValue(Object value) {
   1.195 +		peekState(EnumSet.of(State.ROW));
   1.196 +		currentColumnsCount++;
   1.197 +
   1.198 +		int declaredCount = currentColumnsHeader.getColumnCount();
   1.199 +		if (currentColumnsCount > declaredCount) {
   1.200 +			throw new IllegalStateException("Current columns count is " + currentColumnsCount + " which is more than declared " + declaredCount + " in header.");
   1.201 +		}
   1.202 +	}
   1.203 +
   1.204 +	@Override
   1.205 +	public void writeStartUpdatesResult() {
   1.206 +		pushState(State.RESULT_SET, EnumSet.of(State.DATABASE));
   1.207 +	}
   1.208 +
   1.209 +	@Override
   1.210 +	public void writeEndUpdatesResult() {
   1.211 +		popState(EnumSet.of(State.DATABASE));
   1.212 +		currentColumnsHeader = null;
   1.213 +	}
   1.214 +
   1.215 +	@Override
   1.216 +	public void writeUpdatedRowsCount(int updatedRowsCount) {
   1.217 +		peekState(EnumSet.of(State.UPDATES_RESULT));
   1.218 +	}
   1.219 +
   1.220 +	@Override
   1.221 +	public void writeStartGeneratedKeys() {
   1.222 +		pushState(State.GENERATED_KEYS, EnumSet.of(State.UPDATES_RESULT));
   1.223 +	}
   1.224 +
   1.225 +	@Override
   1.226 +	public void writeEndGeneratedKeys() {
   1.227 +		popState(EnumSet.of(State.UPDATES_RESULT));
   1.228 +	}
   1.229 +
   1.230 +	protected OutputStream getOutputStream() {
   1.231 +		return outputStream;
   1.232 +	}
   1.233 +
   1.234 +	protected ColumnsHeader getCurrentColumnsHeader() {
   1.235 +		return currentColumnsHeader;
   1.236 +	}
   1.237 +
   1.238 +	protected int getCurrentColumnsCount() {
   1.239 +		return currentColumnsCount;
   1.240 +	}
   1.241 +	/**
   1.242 +	 * TODO: write SQLWarning
   1.243 +	 */
   1.244 +}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/ColumnsHeader.java	Fri Dec 20 22:01:06 2013 +0100
     2.3 @@ -0,0 +1,35 @@
     2.4 +/**
     2.5 + * SQL-DK
     2.6 + * Copyright © 2013 František Kučera (frantovo.cz)
     2.7 + *
     2.8 + * This program is free software: you can redistribute it and/or modify
     2.9 + * it under the terms of the GNU General Public License as published by
    2.10 + * the Free Software Foundation, either version 3 of the License, or
    2.11 + * (at your option) any later version.
    2.12 + *
    2.13 + * This program is distributed in the hope that it will be useful,
    2.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    2.16 + * GNU General Public License for more details.
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License
    2.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    2.20 + */
    2.21 +package info.globalcode.sql.dk.formatting;
    2.22 +
    2.23 +/**
    2.24 + *
    2.25 + * @author Ing. František Kučera (frantovo.cz)
    2.26 + */
    2.27 +public class ColumnsHeader {
    2.28 +
    2.29 +	public int getColumnCount() {
    2.30 +		/**
    2.31 +		 * TODO: getColumnCount
    2.32 +		 */
    2.33 +		throw new RuntimeException("Not yet implemented");
    2.34 +	}
    2.35 +	/**
    2.36 +	 * TODO: columns descriptor
    2.37 +	 */
    2.38 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/Formatter.java	Fri Dec 20 22:01:06 2013 +0100
     3.3 @@ -0,0 +1,58 @@
     3.4 +/**
     3.5 + * SQL-DK
     3.6 + * Copyright © 2013 František Kučera (frantovo.cz)
     3.7 + *
     3.8 + * This program is free software: you can redistribute it and/or modify
     3.9 + * it under the terms of the GNU General Public License as published by
    3.10 + * the Free Software Foundation, either version 3 of the License, or
    3.11 + * (at your option) any later version.
    3.12 + *
    3.13 + * This program is distributed in the hope that it will be useful,
    3.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    3.16 + * GNU General Public License for more details.
    3.17 + *
    3.18 + * You should have received a copy of the GNU General Public License
    3.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    3.20 + */
    3.21 +package info.globalcode.sql.dk.formatting;
    3.22 +
    3.23 +import info.globalcode.sql.dk.Parameter;
    3.24 +import java.util.List;
    3.25 +
    3.26 +/**
    3.27 + *
    3.28 + * @author Ing. František Kučera (frantovo.cz)
    3.29 + */
    3.30 +public interface Formatter {
    3.31 +
    3.32 +	void writeStartDatabase();
    3.33 +
    3.34 +	void writeEndDatabase();
    3.35 +
    3.36 +	void writeStartResultSet();
    3.37 +
    3.38 +	void writeEndResultSet();
    3.39 +
    3.40 +	void writeQuery(String sql);
    3.41 +
    3.42 +	void writeParameters(List<Parameter> parameters);
    3.43 +
    3.44 +	void writeColumnsHeader(ColumnsHeader header);
    3.45 +
    3.46 +	void writeStartRow();
    3.47 +
    3.48 +	void writeColumnValue(Object value);
    3.49 +
    3.50 +	void writeEndRow();
    3.51 +
    3.52 +	void writeStartUpdatesResult();
    3.53 +
    3.54 +	void writeUpdatedRowsCount(int updatedRowsCount);
    3.55 +
    3.56 +	void writeStartGeneratedKeys();
    3.57 +
    3.58 +	void writeEndGeneratedKeys();
    3.59 +
    3.60 +	void writeEndUpdatesResult();
    3.61 +}