changeset 297:bb273e9c7e09

Add "final" keyword to classes, method arguments and local variables where possible. In Mapisocket.java replaced 4 log methods with 1 method with 2 extra parameters for more flexibility and less code. Resolved javadoc warning for MonetSavepoint.java
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Thu, 08 Aug 2019 20:19:45 +0200 (2019-08-08)
parents c5efd6e661e5
children 6db8f6702ce8
files src/main/java/nl/cwi/monetdb/jdbc/MonetSavepoint.java src/main/java/nl/cwi/monetdb/mcl/MCLException.java src/main/java/nl/cwi/monetdb/mcl/io/BufferedMCLReader.java src/main/java/nl/cwi/monetdb/mcl/io/BufferedMCLWriter.java src/main/java/nl/cwi/monetdb/mcl/net/MapiSocket.java src/main/java/nl/cwi/monetdb/mcl/parser/HeaderLineParser.java src/main/java/nl/cwi/monetdb/mcl/parser/MCLParseException.java src/main/java/nl/cwi/monetdb/mcl/parser/MCLParser.java src/main/java/nl/cwi/monetdb/mcl/parser/StartOfHeaderParser.java src/main/java/nl/cwi/monetdb/mcl/parser/TupleLineParser.java
diffstat 10 files changed, 135 insertions(+), 186 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetSavepoint.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetSavepoint.java
@@ -42,6 +42,9 @@ public final class MonetSavepoint implem
 
 	/**
 	 * Creates a named MonetSavepoint object
+	 *
+	 * @param name of savepoint
+	 * @throws IllegalArgumentException if no or empty name is given
 	 */
 	public MonetSavepoint(final String name) throws IllegalArgumentException {
 		if (name == null || name.isEmpty())
--- a/src/main/java/nl/cwi/monetdb/mcl/MCLException.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/MCLException.java
@@ -12,10 +12,7 @@ package nl.cwi.monetdb.mcl;
  * A general purpose Exception class for MCL related problems.  This
  * class should be used if no more precise Exception class exists.
  */
-public class MCLException extends Exception {
-	/**
-	 * 
-	 */
+public final class MCLException extends Exception {
 	private static final long serialVersionUID = 1L;
 
 	public MCLException(String e) {
--- a/src/main/java/nl/cwi/monetdb/mcl/io/BufferedMCLReader.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/io/BufferedMCLReader.java
@@ -11,7 +11,6 @@ package nl.cwi.monetdb.mcl.io;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.UnsupportedEncodingException;
 
@@ -41,7 +40,7 @@ import java.io.UnsupportedEncodingExcept
  * @see nl.cwi.monetdb.mcl.net.MapiSocket
  * @see nl.cwi.monetdb.mcl.io.BufferedMCLWriter
  */
-public class BufferedMCLReader extends BufferedReader {
+public final class BufferedMCLReader extends BufferedReader {
 	/** "there is currently no line", or the the type is unknown is represented by UNKNOWN */
 	public final static int UNKNOWN  = 0;
 	/** a line starting with ! indicates ERROR */
@@ -70,7 +69,7 @@ public class BufferedMCLReader extends B
 	 *
 	 * @param in A Reader
 	 */
-	public BufferedMCLReader(Reader in) {
+	public BufferedMCLReader(final Reader in) {
 		super(in);
 	}
 
@@ -82,10 +81,10 @@ public class BufferedMCLReader extends B
 	 * @param enc Encoding
 	 * @throws UnsupportedEncodingException If encoding is not supported
 	 */
-	public BufferedMCLReader(InputStream in, String enc)
+	public BufferedMCLReader(final InputStream in, final String enc)
 		throws UnsupportedEncodingException
 	{
-		super(new InputStreamReader(in, enc));
+		super(new java.io.InputStreamReader(in, enc));
 	}
 
 	/**
@@ -120,7 +119,7 @@ public class BufferedMCLReader extends B
 	 *
 	 * @param line the string to examine
 	 */
-	public void setLineType(String line) {
+	public void setLineType(final String line) {
 		if (line == null || line.isEmpty()) {
 			lineType = UNKNOWN;
 			return;
@@ -182,8 +181,8 @@ public class BufferedMCLReader extends B
 	 * TODO(Wouter): should probably not have to be synchronized.
 	 */
 	final public synchronized String waitForPrompt() throws IOException {
+		final StringBuilder ret = new StringBuilder(128);
 		String tmp;
-		StringBuilder ret = new StringBuilder(128);
 
 		while (lineType != PROMPT) {
 			tmp = readLine();
--- a/src/main/java/nl/cwi/monetdb/mcl/io/BufferedMCLWriter.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/io/BufferedMCLWriter.java
@@ -11,7 +11,6 @@ package nl.cwi.monetdb.mcl.io;
 import java.io.BufferedWriter;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
 
@@ -36,7 +35,7 @@ import java.io.Writer;
  * @see nl.cwi.monetdb.mcl.net.MapiSocket
  * @see nl.cwi.monetdb.mcl.io.BufferedMCLReader
  */
-public class BufferedMCLWriter extends BufferedWriter {
+public final class BufferedMCLWriter extends BufferedWriter {
 	private BufferedMCLReader reader;
 
 	/**
@@ -45,7 +44,7 @@ public class BufferedMCLWriter extends B
 	 *
 	 * @param in A Writer
 	 */
-	public BufferedMCLWriter(Writer in) {
+	public BufferedMCLWriter(final Writer in) {
 		super(in);
 	}
 
@@ -57,10 +56,10 @@ public class BufferedMCLWriter extends B
 	 * @param enc Encoding
 	 * @throws UnsupportedEncodingException If encoding is not supported
 	 */
-	public BufferedMCLWriter(OutputStream in, String enc)
+	public BufferedMCLWriter(final OutputStream in, final String enc)
 		throws UnsupportedEncodingException
 	{
-		super(new OutputStreamWriter(in, enc));
+		super(new java.io.OutputStreamWriter(in, enc));
 	}
 
 	/**
@@ -81,7 +80,7 @@ public class BufferedMCLWriter extends B
 	 *
 	 * @param r an BufferedMCLReader
 	 */
-	public void registerReader(BufferedMCLReader r) {
+	public void registerReader(final BufferedMCLReader r) {
 		reader = r;
 	}
 
@@ -93,7 +92,7 @@ public class BufferedMCLWriter extends B
 	 * @param line The line to write
 	 * @throws IOException If an I/O error occurs
 	 */
-	public void writeLine(String line) throws IOException {
+	public void writeLine(final String line) throws IOException {
 		write(line);
 		flush();
 
--- a/src/main/java/nl/cwi/monetdb/mcl/net/MapiSocket.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/net/MapiSocket.java
@@ -22,11 +22,9 @@ import java.net.Socket;
 import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.net.URI;
-import java.net.URISyntaxException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 
@@ -122,7 +120,7 @@ public final class MapiSocket {
 	public final static int BLOCK = 8 * 1024 - 2;
 
 	/** A short in two bytes for holding the block size in bytes */
-	private byte[] blklen = new byte[2];
+	private final byte[] blklen = new byte[2];
 
 	/**
 	 * Constructs a new MapiSocket.
@@ -138,7 +136,7 @@ public final class MapiSocket {
 	 *
 	 * @param db the database
 	 */
-	public void setDatabase(String db) {
+	public void setDatabase(final String db) {
 		this.database = db;
 	}
 
@@ -147,7 +145,7 @@ public final class MapiSocket {
 	 *
 	 * @param lang the language
 	 */
-	public void setLanguage(String lang) {
+	public void setLanguage(final String lang) {
 		this.language = lang;
 	}
 
@@ -160,7 +158,7 @@ public final class MapiSocket {
 	 *
 	 * @param hash the hash method to use
 	 */
-	public void setHash(String hash) {
+	public void setHash(final String hash) {
 		this.hash = hash;
 	}
 
@@ -172,7 +170,7 @@ public final class MapiSocket {
 	 *
 	 * @param r whether to follow redirects (true) or not (false)
 	 */
-	public void setFollowRedirects(boolean r) {
+	public void setFollowRedirects(final boolean r) {
 		this.followRedirects = r;
 	}
 
@@ -187,7 +185,7 @@ public final class MapiSocket {
 	 * @see #setFollowRedirects(boolean r)
 	 * @param t the number of redirects before an exception is thrown
 	 */
-	public void setTTL(int t) {
+	public void setTTL(final int t) {
 		this.ttl = t;
 	}
 
@@ -202,7 +200,7 @@ public final class MapiSocket {
 	 *        of zero will disable timeout (i.e., timeout of infinity).
 	 * @throws SocketException Issue with the socket
 	 */
-	public void setSoTimeout(int s) throws SocketException {
+	public void setSoTimeout(final int s) throws SocketException {
 		if (s < 0) {
 			throw new IllegalArgumentException("timeout can't be negative");
 		}
@@ -231,7 +229,7 @@ public final class MapiSocket {
 	 *
 	 * @param debug Value to set
 	 */
-	public void setDebug(boolean debug) {
+	public void setDebug(final boolean debug) {
 		this.debug = debug;
 	}
 
@@ -252,16 +250,16 @@ public final class MapiSocket {
 	 * @throws MCLParseException if bogus data is received
 	 * @throws MCLException if an MCL related error occurs
 	 */
-	public List<String> connect(String host, int port, String user, String pass)
-		throws IOException, UnknownHostException, SocketException, MCLParseException, MCLException
+	public List<String> connect(final String host, final int port, final String user, final String pass)
+		throws IOException, SocketException, UnknownHostException, MCLParseException, MCLException
 	{
 		// Wrap around the internal connect that needs to know if it
 		// should really make a TCP connection or not.
 		return connect(host, port, user, pass, true);
 	}
 
-	private List<String> connect(String host, int port, String user, String pass, boolean makeConnection)
-		throws IOException, UnknownHostException, SocketException, MCLParseException, MCLException
+	private List<String> connect(final String host, final int port, final String user, final String pass, final boolean makeConnection)
+		throws IOException, SocketException, UnknownHostException, MCLParseException, MCLException
 	{
 		if (ttl-- <= 0)
 			throw new MCLException("Maximum number of redirects reached, aborting connection attempt.");
@@ -280,16 +278,17 @@ public final class MapiSocket {
 				writer = new BufferedMCLWriter(toMonet, "UTF-8");
 				writer.registerReader(reader);
 			} catch (UnsupportedEncodingException e) {
-				throw new AssertionError(e.toString());
+				throw new MCLException(e.toString());
 			}
 		}
 
-		String c = reader.readLine();
+		final String c = reader.readLine();
 		reader.waitForPrompt();
 		writer.writeLine(getChallengeResponse(c, user, pass, language, database, hash));
+
 		// read monetdb mserver response till prompt
-		List<String> redirects = new ArrayList<String>();
-		List<String> warns = new ArrayList<String>();
+		final ArrayList<String> redirects = new ArrayList<String>();
+		final List<String> warns = new ArrayList<String>();
 		String err = "", tmp;
 		int lineType;
 		do {
@@ -324,20 +323,20 @@ public final class MapiSocket {
 				// "mapi:merovingian://proxy?arg=value&..."
 				// note that the extra arguments must be obeyed in both
 				// cases
-				String suri = redirects.get(0).toString();
+				final String suri = redirects.get(0).toString();
 				if (!suri.startsWith("mapi:"))
 					throw new MCLException("unsupported redirect: " + suri);
 
-				URI u;
+				final URI u;
 				try {
 					u = new URI(suri.substring(5));
-				} catch (URISyntaxException e) {
+				} catch (java.net.URISyntaxException e) {
 					throw new MCLParseException(e.toString());
 				}
 
 				tmp = u.getQuery();
 				if (tmp != null) {
-					String args[] = tmp.split("&");
+					final String args[] = tmp.split("&");
 					for (int i = 0; i < args.length; i++) {
 						int pos = args[i].indexOf("=");
 						if (pos > 0) {
@@ -388,7 +387,7 @@ public final class MapiSocket {
 							setDatabase(tmp);
 						}
 					}
-					int p = u.getPort();
+					final int p = u.getPort();
 					warns.addAll(connect(u.getHost(), p == -1 ? port : p, user, pass, true));
 					warns.add("Redirect by " + host + ":" + port + " to " + suri);
 				} else if (u.getScheme().equals("merovingian")) {
@@ -399,7 +398,7 @@ public final class MapiSocket {
 					throw new MCLException("unsupported scheme in redirect: " + suri);
 				}
 			} else {
-				StringBuilder msg = new StringBuilder("The server sent a redirect for this connection:");
+				final StringBuilder msg = new StringBuilder("The server sent a redirect for this connection:");
 				for (String it : redirects) {
 					msg.append(" [" + it + "]");
 				}
@@ -423,20 +422,18 @@ public final class MapiSocket {
 	 * @param hash the hash method(s) to use, or NULL for all supported hashes
 	 */
 	private String getChallengeResponse(
-			String chalstr,
+			final String chalstr,
 			String username,
 			String password,
-			String language,
-			String database,
-			String hash
+			final String language,
+			final String database,
+			final String hash
 	) throws MCLParseException, MCLException, IOException {
 		// parse the challenge string, split it on ':'
-		String[] chaltok = chalstr.split(":");
+		final String[] chaltok = chalstr.split(":");
 		if (chaltok.length <= 5)
 			throw new MCLParseException("Server challenge string unusable! It contains too few (" + chaltok.length + ") tokens: " + chalstr);
 
-		// challenge string to use as salt/key
-		String challenge = chaltok[0];
 		try {
 			version = Integer.parseInt(chaltok[2]);	// protocol version
 		} catch (NumberFormatException e) {
@@ -468,10 +465,9 @@ public final class MapiSocket {
 					throw new MCLException("Unsupported password hash: " + pwhash);
 				}
 				try {
-					MessageDigest md = MessageDigest.getInstance(algo);
+					final MessageDigest md = MessageDigest.getInstance(algo);
 					md.update(password.getBytes("UTF-8"));
-					byte[] digest = md.digest();
-					password = toHex(digest);
+					password = toHex(md.digest());
 				} catch (NoSuchAlgorithmException e) {
 					throw new MCLException("This JVM does not support password hash: " + pwhash + "\n" + e.toString());
 				} catch (UnsupportedEncodingException e) {
@@ -488,8 +484,8 @@ public final class MapiSocket {
 				// byte-order report for future "binary" transports.
 				// In proto 8, the byte-order of the blocks is always little
 				// endian because most machines today are.
-				String hashes = (hash == null || hash.isEmpty()) ? chaltok[3] : hash;
-				HashSet<String> hashesSet = new HashSet<String>(Arrays.asList(hashes.toUpperCase().split("[, ]")));	// split on comma or space
+				final String hashes = (hash == null || hash.isEmpty()) ? chaltok[3] : hash;
+				final HashSet<String> hashesSet = new HashSet<String>(java.util.Arrays.asList(hashes.toUpperCase().split("[, ]")));	// split on comma or space
 
 				// if we deal with merovingian, mask our credentials
 				if (chaltok[1].equals("merovingian") && !language.equals("control")) {
@@ -519,11 +515,10 @@ public final class MapiSocket {
 					throw new MCLException("no supported hash algorithms found in " + hashes);
 				}
 				try {
-					MessageDigest md = MessageDigest.getInstance(algo);
+					final MessageDigest md = MessageDigest.getInstance(algo);
 					md.update(password.getBytes("UTF-8"));
-					md.update(challenge.getBytes("UTF-8"));
-					byte[] digest = md.digest();
-					pwhash += toHex(digest);
+					md.update(chaltok[0].getBytes("UTF-8"));	// salt/key
+					pwhash += toHex(md.digest());
 				} catch (NoSuchAlgorithmException e) {
 					throw new MCLException("This JVM does not support password hash: " + pwhash + "\n" + e.toString());
 				} catch (UnsupportedEncodingException e) {
@@ -539,13 +534,12 @@ public final class MapiSocket {
 					throw new MCLParseException("Invalid byte-order: " + chaltok[4]);
 				}
 
-				// generate response
-				String response = "BIG:"	// JVM byte-order is big-endian
+				// compose and return response
+				return "BIG:"	// JVM byte-order is big-endian
 					+ username + ":"
 					+ pwhash + ":"
 					+ language + ":"
 					+ (database == null ? "" : database) + ":";
-				return response;
 			default:
 				throw new MCLException("Unsupported protocol version: " + version);
 		}
@@ -558,8 +552,8 @@ public final class MapiSocket {
 	 * @param digest the byte array to convert
 	 * @return the byte array as hexadecimal string
 	 */
-	private static String toHex(byte[] digest) {
-		char[] result = new char[digest.length * 2];
+	private final static String toHex(final byte[] digest) {
+		final char[] result = new char[digest.length * 2];
 		int pos = 0;
 		for (int i = 0; i < digest.length; i++) {
 			result[pos++] = hexChar((digest[i] & 0xf0) >> 4);
@@ -568,7 +562,7 @@ public final class MapiSocket {
 		return new String(result);
 	}
 
-	private static char hexChar(int n) {
+	private final static char hexChar(final int n) {
 		return (n > 9)
 			? (char) ('a' + (n - 10))
 			: (char) ('0' + n);
@@ -636,7 +630,7 @@ public final class MapiSocket {
 	 * @param filename the name of the file to write to
 	 * @throws IOException if the file could not be opened for writing
 	 */
-	public void debug(String filename) throws IOException {
+	public void debug(final String filename) throws IOException {
 		debug(new FileWriter(filename));
 	}
 
@@ -662,7 +656,7 @@ public final class MapiSocket {
 	 *
 	 * @param out to write the log to
 	 */
-	public void debug(Writer out) {
+	public void debug(final Writer out) {
 		log = out;
 		debug = true;
 	}
@@ -677,6 +671,25 @@ public final class MapiSocket {
 	}
 
 	/**
+	 * Writes a logline tagged with a timestamp using the given type and message
+	 * and optionally flushes afterwards.
+	 *
+	 * Used for debugging purposes only and represents a message data that is
+	 * connected to reading (RD or RX) or writing (TD or TX) to the socket.
+	 * R=Receive, T=Transmit, D=Data, X=??
+	 *
+	 * @param type  message type: either RD, RX, TD or TX
+	 * @param message  the message to log
+	 * @param flush  whether we need to flush buffered data to the logfile.
+	 * @throws IOException if an IO error occurs while writing to the logfile
+	 */
+	private final void log(final String type, final String message, final boolean flush) throws IOException {
+		log.write(type + System.currentTimeMillis() + ": " + message + "\n");
+		if (flush)
+			log.flush();
+	}
+
+	/**
 	 * Inner class that is used to write data on a normal stream as a
 	 * blocked stream.  A call to the flush() method will write a
 	 * "final" block to the underlying stream.  Non-final blocks are
@@ -685,16 +698,16 @@ public final class MapiSocket {
 	 * full size, and then flush it explicitly to have a final block
 	 * being written to the stream.
 	 */
-	class BlockOutputStream extends FilterOutputStream {
+	final class BlockOutputStream extends FilterOutputStream {
 		private int writePos = 0;
-		private byte[] block = new byte[BLOCK];
 		private int blocksize = 0;
+		private final byte[] block = new byte[BLOCK];
 
 		/**
 		 * Constructs this BlockOutputStream, backed by the given
 		 * OutputStream.  A BufferedOutputStream is internally used.
 		 */
-		public BlockOutputStream(OutputStream out) {
+		public BlockOutputStream(final OutputStream out) {
 			// always use a buffered stream, even though we know how
 			// much bytes to write/read, since this is just faster for
 			// some reason
@@ -726,7 +739,7 @@ public final class MapiSocket {
 		 * @param last whether this is the last block
 		 * @throws IOException if writing to the stream failed
 		 */
-		public void writeBlock(boolean last) throws IOException {
+		public void writeBlock(final boolean last) throws IOException {
 			if (last) {
 				// always fits, because of BLOCK's size
 				blocksize = (short)writePos;
@@ -744,24 +757,23 @@ public final class MapiSocket {
 			}
 
 			out.write(blklen);
-
 			// write the actual block
 			out.write(block, 0, writePos);
 
 			if (debug) {
 				if (last) {
-					logTd("write final block: " + writePos + " bytes");
+					log("TD ", "write final block: " + writePos + " bytes", false);
 				} else {
-					logTd("write block: " + writePos + " bytes");
+					log("TD ", "write block: " + writePos + " bytes", false);
 				}
-				logTx(new String(block, 0, writePos, "UTF-8"));
+				log("TX ", new String(block, 0, writePos, "UTF-8"), true);
 			}
 
 			writePos = 0;
 		}
 
 		@Override
-		public void write(int b) throws IOException {
+		public void write(final int b) throws IOException {
 			if (writePos == BLOCK) {
 				writeBlock(false);
 			}
@@ -769,12 +781,12 @@ public final class MapiSocket {
 		}
 
 		@Override
-		public void write(byte[] b) throws IOException {
+		public void write(final byte[] b) throws IOException {
 			write(b, 0, b.length);
 		}
 
 		@Override
-		public void write(byte[] b, int off, int len) throws IOException {
+		public void write(final byte[] b, int off, int len) throws IOException {
 			int t = 0;
 			while (len > 0) {
 				t = BLOCK - writePos;
@@ -805,16 +817,16 @@ public final class MapiSocket {
 	 * Inner class that is used to make the data on the blocked stream
 	 * available as a normal stream.
 	 */
-	class BlockInputStream extends FilterInputStream {
+	final class BlockInputStream extends FilterInputStream {
 		private int readPos = 0;
 		private int blockLen = 0;
-		private byte[] block = new byte[BLOCK + 3]; // \n.\n
+		private final byte[] block = new byte[BLOCK + 3]; // \n.\n
 
 		/**
 		 * Constructs this BlockInputStream, backed by the given
 		 * InputStream.  A BufferedInputStream is internally used.
 		 */
-		public BlockInputStream(InputStream in) {
+		public BlockInputStream(final InputStream in) {
 			// always use a buffered stream, even though we know how
 			// much bytes to write/read, since this is just faster for
 			// some reason
@@ -832,7 +844,7 @@ public final class MapiSocket {
 		}
 
 		@Override
-		public void mark(int readlimit) {
+		public void mark(final int readlimit) {
 			throw new AssertionError("Not implemented!");
 		}
 
@@ -853,10 +865,9 @@ public final class MapiSocket {
 		 *
 		 * @return false if reading the block failed due to EOF
 		 */
-		private boolean _read(byte[] b, int len) throws IOException {
+		private boolean _read(final byte[] b, int len) throws IOException {
 			int s;
 			int off = 0;
-
 			while (len > 0) {
 				s = in.read(b, off, len);
 				if (s == -1) {
@@ -864,15 +875,15 @@ public final class MapiSocket {
 					// able to read the whole, so make this fatal
 					if (off > 0) {
 						if (debug) {
-							logRd("the following incomplete block was received:");
-							logRx(new String(b, 0, off, "UTF-8"));
+							log("RD ", "the following incomplete block was received:", false);
+							log("RX ", new String(b, 0, off, "UTF-8"), true);
 						}
 						throw new IOException("Read from " +
 								con.getInetAddress().getHostName() + ":" +
 								con.getPort() + ": Incomplete block read from stream");
 					}
 					if (debug)
-						logRd("server closed the connection (EOF)");
+						log("RD ", "server closed the connection (EOF)", true);
 					return false;
 				}
 				len -= s;
@@ -919,26 +930,24 @@ public final class MapiSocket {
 
 			if (debug) {
 				if ((blklen[0] & 0x1) == 1) {
-					logRd("read final block: " + blockLen + " bytes");
+					log("RD ", "read final block: " + blockLen + " bytes", false);
 				} else {
-					logRd("read new block: " + blockLen + " bytes");
+					log("RD ", "read new block: " + blockLen + " bytes", false);
 				}
 			}
 
 			// sanity check to avoid bad servers make us do an ugly
 			// stack trace
 			if (blockLen > block.length)
-				throw new AssertionError("Server sent a block " +
-						"larger than BLOCKsize: " +
+				throw new IOException("Server sent a block larger than BLOCKsize: " +
 						blockLen + " > " + block.length);
 			if (!_read(block, blockLen))
-				return(-1);
+				return -1;
 
 			if (debug)
-				logRx(new String(block, 0, blockLen, "UTF-8"));
+				log("RX ", new String(block, 0, blockLen, "UTF-8"), true);
 
-			// if this is the last block, make it end with a newline and
-			// prompt
+			// if this is the last block, make it end with a newline and prompt
 			if ((blklen[0] & 0x1) == 1) {
 				if (blockLen > 0 && block[blockLen - 1] != '\n') {
 					// to terminate the block in a Reader
@@ -948,31 +957,32 @@ public final class MapiSocket {
 				block[blockLen++] = BufferedMCLReader.PROMPT;
 				block[blockLen++] = '\n';
 				if (debug)
-					logRd("inserting prompt");
+					log("RD ", "inserting prompt", true);
 			}
 
-			return(blockLen);
+			return blockLen;
 		}
 
 		@Override
 		public int read() throws IOException {
 			if (available() == 0) {
 				if (readBlock() == -1)
-					return(-1);
+					return -1;
 			}
 
 			if (debug)
-				logRx(new String(block, readPos, 1, "UTF-8"));
+				log("RX ", new String(block, readPos, 1, "UTF-8"), true);
+
 			return (int)block[readPos++];
 		}
 
 		@Override
-		public int read(byte[] b) throws IOException {
+		public int read(final byte[] b) throws IOException {
 			return read(b, 0, b.length);
 		}
 
 		@Override
-		public int read(byte[] b, int off, int len) throws IOException {
+		public int read(final byte[] b, int off, int len) throws IOException {
 			int t;
 			int size = 0;
 			while (size < len) {
@@ -1004,7 +1014,7 @@ public final class MapiSocket {
 		}
 
 		@Override
-		public long skip(long n) throws IOException {
+		public long skip(final long n) throws IOException {
 			long skip = n;
 			int t = 0;
 			while (skip > 0) {
@@ -1076,60 +1086,4 @@ public final class MapiSocket {
 		close();
 		super.finalize();
 	}
-
-
-	/**
-	 * Writes a logline tagged with a timestamp using the given string.
-	 * Used for debugging purposes only and represents a message that is
-	 * connected to writing to the socket.  A logline might look like:
-	 * TX 152545124: Hello MonetDB!
-	 *
-	 * @param message the message to log
-	 * @throws IOException if an IO error occurs while writing to the logfile
-	 */
-	private void logTx(String message) throws IOException {
-		log.write("TX " + System.currentTimeMillis() + ": " + message + "\n");
-	}
-
-	/**
-	 * Writes a logline tagged with a timestamp using the given string.
-	 * Lines written using this log method are tagged as "added
-	 * metadata" which is not strictly part of the data sent.
-	 *
-	 * @param message the message to log
-	 * @throws IOException if an IO error occurs while writing to the logfile
-	 */
-	private void logTd(String message) throws IOException {
-		log.write("TD " + System.currentTimeMillis() + ": " + message + "\n");
-	}
-
-	/**
-	 * Writes a logline tagged with a timestamp using the given string,
-	 * and flushes afterwards.  Used for debugging purposes only and
-	 * represents a message that is connected to reading from the
-	 * socket.  The log is flushed after writing the line.  A logline
-	 * might look like:
-	 * RX 152545124: Hi JDBC!
-	 *
-	 * @param message the message to log
-	 * @throws IOException if an IO error occurs while writing to the logfile
-	 */
-	private void logRx(String message) throws IOException {
-		log.write("RX " + System.currentTimeMillis() + ": " + message + "\n");
-		log.flush();
-	}
-
-	/**
-	 * Writes a logline tagged with a timestamp using the given string,
-	 * and flushes afterwards.  Lines written using this log method are
-	 * tagged as "added metadata" which is not strictly part of the data
-	 * received.
-	 *
-	 * @param message the message to log
-	 * @throws IOException if an IO error occurs while writing to the logfile
-	 */
-	private void logRd(String message) throws IOException {
-		log.write("RD " + System.currentTimeMillis() + ": " + message + "\n");
-		log.flush();
-	}
 }
--- a/src/main/java/nl/cwi/monetdb/mcl/parser/HeaderLineParser.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/parser/HeaderLineParser.java
@@ -16,7 +16,7 @@ package nl.cwi.monetdb.mcl.parser;
  *
  * @author Fabian Groffen
  */
-public class HeaderLineParser extends MCLParser {
+public final class HeaderLineParser extends MCLParser {
 	/* types of meta data supported by MCL protocol */
 	public final static int NAME   = 1;	// name of column
 	public final static int LENGTH = 2;
@@ -31,7 +31,7 @@ public class HeaderLineParser extends MC
 	 *
 	 * @param columncount the number of columns in the to be parsed string
 	 */
-	public HeaderLineParser(int columncount) {
+	public HeaderLineParser(final int columncount) {
 		super(columncount);
 		intValues = new int[columncount];
 	}
@@ -50,8 +50,8 @@ public class HeaderLineParser extends MC
 	 * @throws MCLParseException if an error occurs during parsing
 	 */
 	@Override
-	public int parse(String source) throws MCLParseException {
-		char[] chrLine = source.toCharArray();
+	public int parse(final String source) throws MCLParseException {
+		final char[] chrLine = source.toCharArray();
 		int len = chrLine.length;
 		int pos = 0;
 		boolean foundChar = false;
@@ -122,7 +122,7 @@ public class HeaderLineParser extends MC
 	}
 
 	/**
-	 * Returns an array of Strings containing the values between
+	 * Fills an array of Strings containing the values between
 	 * ',\t' separators.
 	 *
 	 * As of Oct2014-SP1 release MAPI adds double quotes around names when
@@ -135,7 +135,7 @@ public class HeaderLineParser extends MC
 	 * @param start where the relevant data starts
 	 * @param stop where the relevant data stops
 	 */
-	final private void getValues(char[] chrLine, int start, int stop) {
+	private final void getValues(final char[] chrLine, int start, final int stop) {
 		int elem = 0;
 		boolean inString = false, escaped = false;
 
@@ -193,7 +193,7 @@ public class HeaderLineParser extends MC
 	}
 
 	/**
-	 * Returns an array of ints containing the values between
+	 * Fills an array of ints containing the values between
 	 * ',\t' separators.
 	 *
 	 * Feb2017 note - This integer parser doesn't have to parse negative
@@ -204,7 +204,7 @@ public class HeaderLineParser extends MC
 	 * @param start where the relevant data starts
 	 * @param stop where the relevant data stops
 	 */
-	final private void getIntValues(char[] chrLine, int start, int stop) throws MCLParseException {
+	private final void getIntValues(final char[] chrLine, final int start, final int stop) throws MCLParseException {
 		int elem = 0;
 		int tmp = 0;
 
@@ -212,7 +212,7 @@ public class HeaderLineParser extends MC
 			if (chrLine[i] == ',' && chrLine[i + 1] == '\t') {
 				intValues[elem++] = tmp;
 				tmp = 0;
-				start = i++;
+				i++;
 			} else {
 				// note: don't use Character.isDigit() here, because
 				// we only want ISO-LATIN-1 digits
--- a/src/main/java/nl/cwi/monetdb/mcl/parser/MCLParseException.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/parser/MCLParseException.java
@@ -8,8 +8,6 @@
 
 package nl.cwi.monetdb.mcl.parser;
 
-import java.text.ParseException;
-
 /**
  * When an MCLParseException is thrown, the MCL protocol is violated by
  * the sender.  In general a stream reader throws an
@@ -19,10 +17,7 @@ import java.text.ParseException;
  * give an error offset whenever possible.  Alternatively it makes sure
  * that the error message includes the offending data read.
  */
-public class MCLParseException extends ParseException {
-	/**
-	 * 
-	 */
+public class MCLParseException extends java.text.ParseException {
 	private static final long serialVersionUID = 1L;
 
 	public MCLParseException(String e) {
--- a/src/main/java/nl/cwi/monetdb/mcl/parser/MCLParser.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/parser/MCLParser.java
@@ -35,7 +35,7 @@ public abstract class MCLParser {
 	 *
 	 * @param capacity the number of field values to expect
 	 */
-	protected MCLParser(int capacity) {
+	protected MCLParser(final int capacity) {
 		values = new String[capacity];
 	}
 
@@ -50,7 +50,7 @@ public abstract class MCLParser {
 	 * @see #next()
 	 * @see #hasNext()
 	 */
-	abstract public int parse(String source) throws MCLParseException;
+	abstract public int parse(final String source) throws MCLParseException;
 
 	/**
 	 * Repositions the internal field offset to the start, such that the
--- a/src/main/java/nl/cwi/monetdb/mcl/parser/StartOfHeaderParser.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/parser/StartOfHeaderParser.java
@@ -22,7 +22,7 @@ import java.nio.CharBuffer;
  *
  * @author Fabian Groffen
  */
-public class StartOfHeaderParser {
+public final class StartOfHeaderParser {
 	private CharBuffer soh = null;
 	private int len;
 	private int pos;
@@ -49,10 +49,10 @@ public class StartOfHeaderParser {
 	/** An unknown and unsupported response */
 	public final static int Q_UNKNOWN  =  0 ;
 
-	public final int parse(String in) throws MCLParseException {
+	public final int parse(final String in) throws MCLParseException {
 		soh = CharBuffer.wrap(in);
 		soh.get();	// skip the &
-		int type = soh.get();
+		final int type = soh.get();
 		switch (type) {
 			case Q_PARSE:
 			case Q_SCHEMA:
@@ -96,20 +96,22 @@ public class StartOfHeaderParser {
 	 * @throws MCLParseException if no numeric value could be read
 	 */
 	public final int getNextAsInt() throws MCLParseException {
-		boolean positive = true;
 		pos++;
 		if (!soh.hasRemaining())
 			throw new MCLParseException("unexpected end of string", soh.position() - 1);
-		int tmp = 0;
+
+		boolean positive = true;
 		char chr = soh.get();
 		// note: don't use Character.isDigit() here, because
 		// we only want ISO-LATIN-1 digits
-		if(chr == '-') {
+		if (chr == '-') {
 			positive = false;
 			if (!soh.hasRemaining())
 				throw new MCLParseException("unexpected end of string", soh.position() - 1);
 			chr = soh.get();
 		}
+
+		int tmp = 0;
 		if (chr >= '0' && chr <= '9') {
 			tmp = (int)chr - (int)'0';
 		} else {
@@ -132,12 +134,12 @@ public class StartOfHeaderParser {
 		pos++;
 		if (!soh.hasRemaining())
 			throw new MCLParseException("unexpected end of string", soh.position() - 1);
+
 		int cnt = 0;
 		soh.mark();
 		while (soh.hasRemaining() && soh.get() != ' ') {
 			cnt++;
 		}
-
 		soh.reset();
 
 		return soh.subSequence(0, cnt).toString();
--- a/src/main/java/nl/cwi/monetdb/mcl/parser/TupleLineParser.java
+++ b/src/main/java/nl/cwi/monetdb/mcl/parser/TupleLineParser.java
@@ -15,13 +15,13 @@ package nl.cwi.monetdb.mcl.parser;
  *
  * @author Fabian Groffen
  */
-public class TupleLineParser extends MCLParser {
+public final class TupleLineParser extends MCLParser {
 	/**
 	 * Constructs a TupleLineParser which expects columncount columns.
 	 *
 	 * @param columncount the number of columns in the to be parsed string
 	 */
-	public TupleLineParser(int columncount) {
+	public TupleLineParser(final int columncount) {
 		super(columncount);
 	}
 
@@ -37,7 +37,7 @@ public class TupleLineParser extends MCL
 	 * @throws MCLParseException if an error occurs during parsing
 	 */
 	@Override
-	public int parse(String source) throws MCLParseException {
+	public int parse(final String source) throws MCLParseException {
 		final int len = source.length();
 		// first detect whether this is a single value line (=) or a
 		// real tuple ([)
@@ -170,7 +170,7 @@ public class TupleLineParser extends MCL
 							} else {
 								// the field is a string surrounded by double quotes and without escape chars
 								cursor++;
-								String fieldVal = new String(chrLine, cursor, endpos - cursor);
+								final String fieldVal = new String(chrLine, cursor, endpos - cursor);
 								// if (fieldVal.contains("\\")) {
 								//	throw new MCLParseException("Invalid parsing: detected a \\ in double quoted string: " + fieldVal);
 								// }
@@ -181,7 +181,7 @@ public class TupleLineParser extends MCL
 							values[column] = null;
 						} else {
 							// the field is a string NOT surrounded by double quotes and thus without escape chars
-							String fieldVal = new String(chrLine, cursor, i - 1 - cursor);
+							final String fieldVal = new String(chrLine, cursor, i - 1 - cursor);
 							// if (fieldVal.contains("\\")) {
 							//	throw new MCLParseException("Invalid parsing: detected a \\ in unquoted string: " + fieldVal);
 							// }