more configuration, more JAXB, more formatters v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 22 Dec 2013 18:19:38 +0100
branchv_0
changeset 29 d66858b4b563
parent 28 57c44a6baedb
child 30 b7ea47b2d4ca
more configuration, more JAXB, more formatters
java/sql-dk/src/info/globalcode/sql/dk/CLIOptions.java
java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java
java/sql-dk/src/info/globalcode/sql/dk/Constants.java
java/sql-dk/src/info/globalcode/sql/dk/DatabaseConnection.java
java/sql-dk/src/info/globalcode/sql/dk/Functions.java
java/sql-dk/src/info/globalcode/sql/dk/SQLCommand.java
java/sql-dk/src/info/globalcode/sql/dk/batch/Batch.java
java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java
java/sql-dk/src/info/globalcode/sql/dk/configuration/DatabaseDefinition.java
java/sql-dk/src/info/globalcode/sql/dk/configuration/FormatterDefinition.java
java/sql-dk/src/info/globalcode/sql/dk/formatting/AbstractFormatter.java
java/sql-dk/src/info/globalcode/sql/dk/formatting/Formatter.java
java/sql-dk/src/info/globalcode/sql/dk/formatting/SilentFormatter.java
java/sql-dk/src/info/globalcode/sql/dk/formatting/XmlFormatter.java
--- a/java/sql-dk/src/info/globalcode/sql/dk/CLIOptions.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/CLIOptions.java	Sun Dec 22 18:19:38 2013 +0100
@@ -20,6 +20,7 @@
 import static info.globalcode.sql.dk.Functions.isNotEmpty;
 import static info.globalcode.sql.dk.Functions.isEmpty;
 import static info.globalcode.sql.dk.Functions.equalz;
+import info.globalcode.sql.dk.SQLCommand.COMMAND_TYPE;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.EnumSet;
@@ -57,14 +58,6 @@
 		DATABASES,
 		CONNECTION
 	}
-
-	public enum COMMAND_TYPE {
-
-		/** SELECT */
-		QUERY,
-		/** INSERT, UPDATE, DELETE */
-		UPDATE
-	};
 	private COMMAND_TYPE commandType;
 	private final Collection<NamedParameter> namedParameters = new ArrayList<>();
 	private final List<Parameter> numberedParameters = new ArrayList<>();
--- a/java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java	Sun Dec 22 18:19:38 2013 +0100
@@ -17,6 +17,7 @@
  */
 package info.globalcode.sql.dk;
 
+import info.globalcode.sql.dk.SQLCommand.COMMAND_TYPE;
 import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -75,12 +76,12 @@
 					break;
 				case Tokens.SQL:
 					options.setSql(fetchNext(args, ++i));
-					options.setCommandType(CLIOptions.COMMAND_TYPE.QUERY);
+					options.setCommandType(COMMAND_TYPE.QUERY);
 					break;
 				case Tokens.SQL_UPDATE:
 				case Tokens.SQL_INSERT:
 					options.setSql(fetchNext(args, ++i));
-					options.setCommandType(CLIOptions.COMMAND_TYPE.UPDATE);
+					options.setCommandType(COMMAND_TYPE.UPDATE);
 					break;
 				case Tokens.BATCH:
 					options.setBatch(true);
--- a/java/sql-dk/src/info/globalcode/sql/dk/Constants.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/Constants.java	Sun Dec 22 18:19:38 2013 +0100
@@ -27,6 +27,7 @@
 	public static final String LICENSE_FILE = "info/globalcode/sql/dk/license.txt";
 	public static final String VERSION_FILE = "info/globalcode/sql/dk/version.txt";
 	public static final String HELP_FILE = "info/globalcode/sql/dk/help.txt";
+	public static final String XMLNS_CONFIGURATION = "https://sql-dk.globalcode.info/xmlns/configuration";
 
 	private Constants() {
 	}
--- a/java/sql-dk/src/info/globalcode/sql/dk/DatabaseConnection.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/DatabaseConnection.java	Sun Dec 22 18:19:38 2013 +0100
@@ -17,9 +17,13 @@
  */
 package info.globalcode.sql.dk;
 
+import info.globalcode.sql.dk.batch.Batch;
 import info.globalcode.sql.dk.configuration.DatabaseDefinition;
+import info.globalcode.sql.dk.formatting.Formatter;
 import java.sql.Connection;
 import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.SQLException;
 
 /**
@@ -36,4 +40,76 @@
 
 		connection = DriverManager.getConnection(databaseDefinition.getUrl(), databaseDefinition.getName(), databaseDefinition.getPassword());
 	}
+
+	public void executeQuery(SQLCommand sqlCommand, Formatter formatter) throws SQLException {
+		formatter.writeStartDatabase(databaseDefinition);
+		processCommand(sqlCommand, formatter);
+		formatter.writeEndDatabase();
+	}
+
+	public void executeBatch(Batch batch, Formatter formatter) throws SQLException {
+		formatter.writeStartDatabase(databaseDefinition);
+		while (batch.hasNext()) {
+			processCommand(batch.next(), formatter);
+		}
+		formatter.writeEndDatabase();
+	}
+
+	private void processCommand(SQLCommand sqlCommand, Formatter formatter) throws SQLException {
+		SQLCommand.COMMAND_TYPE commandType = sqlCommand.getCommandType();
+		switch (commandType) {
+			case QUERY:
+				processQueryCommand(sqlCommand, formatter);
+				break;
+			case UPDATE:
+				processUpdateCommand(sqlCommand, formatter);
+				break;
+			default:
+				throw new IllegalArgumentException("Unexpected command type: " + commandType);
+		}
+	}
+
+	private void processQueryCommand(SQLCommand sqlCommand, Formatter formatter) throws SQLException {
+		formatter.writeStartResultSet();
+		formatter.writeQuery(sqlCommand.getQuery());
+		/** TODO: formatter.writeParameters(null); */
+		try (PreparedStatement ps = sqlCommand.prepareStatement(connection)) {
+			sqlCommand.parametrize(ps);
+			try (ResultSet rs = ps.executeQuery()) {
+				processResultSet(rs, formatter);
+			}
+		}
+
+		formatter.writeEndResultSet();
+	}
+
+	private void processUpdateCommand(SQLCommand sqlCommand, Formatter formatter) throws SQLException {
+		formatter.writeStartUpdatesResult();
+		formatter.writeQuery(sqlCommand.getQuery());
+		/** TODO: formatter.writeParameters(null); */
+		try (PreparedStatement ps = sqlCommand.prepareStatement(connection)) {
+			sqlCommand.parametrize(ps);
+			int updatedRowsCount = ps.executeUpdate();
+			formatter.writeUpdatedRowsCount(updatedRowsCount);
+
+			formatter.writeStartGeneratedKeys();
+			try (ResultSet rs = ps.getGeneratedKeys()) {
+				processResultSet(rs, formatter);
+			}
+			formatter.writeEndGeneratedKeys();
+
+		}
+
+		formatter.writeEndUpdatesResult();
+	}
+
+	private void processResultSet(ResultSet rs, Formatter formatter) throws SQLException {
+		/** TODO: formatter.writeColumnsHeader(null); */
+		while (rs.next()) {
+			formatter.writeStartRow();
+
+			/** TODO: formatter.writeColumnValue(rs.get); */
+			formatter.writeEndRow();
+		}
+	}
 }
--- a/java/sql-dk/src/info/globalcode/sql/dk/Functions.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/Functions.java	Sun Dec 22 18:19:38 2013 +0100
@@ -17,6 +17,7 @@
  */
 package info.globalcode.sql.dk;
 
+import info.globalcode.sql.dk.configuration.NameIdentified;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Map;
@@ -84,4 +85,14 @@
 			return c;
 		}
 	}
+
+	public static <T extends NameIdentified> T findByName(Collection<T> collection, String name) {
+		for (T element : collection) {
+			if (equalz(element.getName(), name)) {
+				return element;
+			}
+		}
+
+		return null;
+	}
 }
--- a/java/sql-dk/src/info/globalcode/sql/dk/SQLCommand.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/SQLCommand.java	Sun Dec 22 18:19:38 2013 +0100
@@ -26,9 +26,30 @@
  */
 public abstract class SQLCommand {
 
+	private COMMAND_TYPE commandType;
 	private String query;
 
 	public abstract PreparedStatement prepareStatement(Connection c);
 
 	public abstract void parametrize(PreparedStatement ps);
+
+	public COMMAND_TYPE getCommandType() {
+		return commandType;
+	}
+
+	public void setCommandType(COMMAND_TYPE commandType) {
+		this.commandType = commandType;
+	}
+
+	public String getQuery() {
+		return query;
+	}
+
+	public enum COMMAND_TYPE {
+
+		/** SELECT */
+		QUERY,
+		/** INSERT, UPDATE, DELETE */
+		UPDATE
+	};
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/java/sql-dk/src/info/globalcode/sql/dk/batch/Batch.java	Sun Dec 22 18:19:38 2013 +0100
@@ -0,0 +1,46 @@
+/**
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+package info.globalcode.sql.dk.batch;
+
+import info.globalcode.sql.dk.SQLCommand;
+import java.util.Iterator;
+
+/**
+ *
+ * @author Ing. František Kučera (frantovo.cz)
+ */
+public class Batch implements Iterator<SQLCommand> {
+
+	@Override
+	public boolean hasNext() {
+		/** TODO: implement iterator */
+		throw new UnsupportedOperationException("Not supported yet.");
+	}
+
+	@Override
+	public SQLCommand next() {
+		/** TODO: implement iterator */
+		throw new UnsupportedOperationException("Not supported yet.");
+	}
+
+	@Override
+	public void remove() {
+		/** TODO: implement iterator */
+		throw new UnsupportedOperationException("Not supported yet.");
+	}
+}
--- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java	Sun Dec 22 18:19:38 2013 +0100
@@ -17,20 +17,40 @@
  */
 package info.globalcode.sql.dk.configuration;
 
+import static info.globalcode.sql.dk.Constants.XMLNS_CONFIGURATION;
+import static info.globalcode.sql.dk.Functions.findByName;
+import info.globalcode.sql.dk.formatting.SilentFormatter;
+import info.globalcode.sql.dk.formatting.XmlFormatter;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
 /**
  *
  * @author Ing. František Kučera (frantovo.cz)
  */
-@XmlRootElement
+@XmlRootElement(name = "configuration", namespace = XMLNS_CONFIGURATION)
 public class Configuration {
 
 	private List<DatabaseDefinition> databases = new ArrayList<>();
 	private List<FormatterDefinition> formatters = new ArrayList<>();
+	private String defaultFormatter;
+	/**
+	 * Default list of formatters. Is used if particular name is not found in user configuration.
+	 */
+	private static final Collection<FormatterDefinition> buildInFormatters;
 
+	static {
+		Collection<FormatterDefinition> l = new ArrayList<>();
+		l.add(new FormatterDefinition(SilentFormatter.NAME, SilentFormatter.class.getName()));
+		l.add(new FormatterDefinition(XmlFormatter.NAME, XmlFormatter.class.getName()));
+		buildInFormatters = Collections.unmodifiableCollection(l);
+	}
+
+	@XmlElement(name = "database", namespace = XMLNS_CONFIGURATION)
 	public List<DatabaseDefinition> getDatabases() {
 		return databases;
 	}
@@ -39,6 +59,11 @@
 		this.databases = databases;
 	}
 
+	public DatabaseDefinition getDatabase(String name) {
+		return findByName(databases, name);
+	}
+
+	@XmlElement(name = "formatter", namespace = XMLNS_CONFIGURATION)
 	public List<FormatterDefinition> getFormatters() {
 		return formatters;
 	}
@@ -46,4 +71,21 @@
 	public void setFormatters(List<FormatterDefinition> formatters) {
 		this.formatters = formatters;
 	}
+
+	public FormatterDefinition getFormatter(String name) {
+		FormatterDefinition fd = findByName(formatters, name);
+		return fd == null ? findByName(buildInFormatters, name) : fd;
+	}
+
+	/**
+	 * @return name of default formatter, is used if name is not specified on CLI
+	 */
+	@XmlElement(name = "defaultFormatter", namespace = XMLNS_CONFIGURATION)
+	public String getDefaultFormatter() {
+		return defaultFormatter;
+	}
+
+	public void setDefaultFormatter(String defaultFormatter) {
+		this.defaultFormatter = defaultFormatter;
+	}
 }
--- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/DatabaseDefinition.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/configuration/DatabaseDefinition.java	Sun Dec 22 18:19:38 2013 +0100
@@ -17,9 +17,10 @@
  */
 package info.globalcode.sql.dk.configuration;
 
+import static info.globalcode.sql.dk.Constants.XMLNS_CONFIGURATION;
 import info.globalcode.sql.dk.DatabaseConnection;
+import java.sql.SQLException;
 import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlTransient;
 
 /**
  *
@@ -32,7 +33,7 @@
 	private String userName;
 	private String password;
 
-	@XmlElement(name = "name")
+	@XmlElement(name = "name", namespace = XMLNS_CONFIGURATION)
 	@Override
 	public String getName() {
 		return name;
@@ -42,7 +43,7 @@
 		this.name = name;
 	}
 
-	@XmlElement(name = "url")
+	@XmlElement(name = "url", namespace = XMLNS_CONFIGURATION)
 	public String getUrl() {
 		return url;
 	}
@@ -51,7 +52,7 @@
 		this.url = url;
 	}
 
-	@XmlElement(name = "userName")
+	@XmlElement(name = "userName", namespace = XMLNS_CONFIGURATION)
 	public String getUserName() {
 		return userName;
 	}
@@ -60,7 +61,7 @@
 		this.userName = userName;
 	}
 
-	@XmlElement(name = "password")
+	@XmlElement(name = "password", namespace = XMLNS_CONFIGURATION)
 	public String getPassword() {
 		return password;
 	}
@@ -69,8 +70,7 @@
 		this.password = password;
 	}
 
-	@XmlTransient
-	public DatabaseConnection connect() {
+	public DatabaseConnection connect() throws SQLException {
 		return new DatabaseConnection(this);
 	}
 }
--- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/FormatterDefinition.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/configuration/FormatterDefinition.java	Sun Dec 22 18:19:38 2013 +0100
@@ -17,13 +17,13 @@
  */
 package info.globalcode.sql.dk.configuration;
 
+import static info.globalcode.sql.dk.Constants.XMLNS_CONFIGURATION;
 import info.globalcode.sql.dk.DKException;
 import info.globalcode.sql.dk.formatting.Formatter;
 import info.globalcode.sql.dk.formatting.FormatterContext;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlTransient;
 
 /**
  *
@@ -34,7 +34,15 @@
 	private String name;
 	private String className;
 
-	@XmlElement(name = "name")
+	public FormatterDefinition() {
+	}
+
+	public FormatterDefinition(String name, String className) {
+		this.name = name;
+		this.className = className;
+	}
+
+	@XmlElement(name = "name", namespace = XMLNS_CONFIGURATION)
 	@Override
 	public String getName() {
 		return name;
@@ -54,7 +62,7 @@
 	 *
 	 * @return fully qualified class name
 	 */
-	@XmlElement(name = "class")
+	@XmlElement(name = "class", namespace = XMLNS_CONFIGURATION)
 	public String getClassName() {
 		return className;
 	}
@@ -68,7 +76,6 @@
 	 * @return
 	 * @throws DKException
 	 */
-	@XmlTransient
 	public Formatter getInstance(FormatterContext context) throws DKException {
 		try {
 			Constructor constructor = Class.forName(className).getConstructor(context.getClass());
--- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/AbstractFormatter.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/AbstractFormatter.java	Sun Dec 22 18:19:38 2013 +0100
@@ -18,6 +18,7 @@
 package info.globalcode.sql.dk.formatting;
 
 import info.globalcode.sql.dk.Parameter;
+import info.globalcode.sql.dk.configuration.DatabaseDefinition;
 import java.util.EmptyStackException;
 import java.util.EnumSet;
 import java.util.List;
@@ -121,7 +122,7 @@
 	}
 
 	@Override
-	public void writeStartDatabase() {
+	public void writeStartDatabase(DatabaseDefinition databaseDefinition) {
 		pushState(State.DATABASE, EnumSet.of(State.ROOT));
 	}
 
--- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/Formatter.java	Sat Dec 21 22:22:30 2013 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/Formatter.java	Sun Dec 22 18:19:38 2013 +0100
@@ -18,6 +18,7 @@
 package info.globalcode.sql.dk.formatting;
 
 import info.globalcode.sql.dk.Parameter;
+import info.globalcode.sql.dk.configuration.DatabaseDefinition;
 import java.util.List;
 
 /**
@@ -26,7 +27,7 @@
  */
 public interface Formatter {
 
-	void writeStartDatabase();
+	void writeStartDatabase(DatabaseDefinition databaseDefinition);
 
 	void writeEndDatabase();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/SilentFormatter.java	Sun Dec 22 18:19:38 2013 +0100
@@ -0,0 +1,33 @@
+/**
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+package info.globalcode.sql.dk.formatting;
+
+/**
+ * Does not output anything, can be used instead of
+ * <code>/dev/null</code>.
+ *
+ * @author Ing. František Kučera (frantovo.cz)
+ */
+public class SilentFormatter extends AbstractFormatter {
+	
+	public static final String NAME = "silent";
+
+	public SilentFormatter(FormatterContext formatterContext) {
+		super(formatterContext);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/XmlFormatter.java	Sun Dec 22 18:19:38 2013 +0100
@@ -0,0 +1,31 @@
+/**
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+package info.globalcode.sql.dk.formatting;
+
+/**
+ *
+ * @author Ing. František Kučera (frantovo.cz)
+ */
+public class XmlFormatter extends AbstractFormatter {
+
+	public static final String NAME = "xml";
+
+	public XmlFormatter(FormatterContext formatterContext) {
+		super(formatterContext);
+	}
+}