diff src/main/java/org/monetdb/mcl/io/BufferedMCLReader.java @ 700:940e266eeccd

Refactor BufferedMCLReader It used to inherit from BufferedReader but there is no reason for that. Also, it used to have a method readLine() which - returned the line read - stored the linetype In the new setup we have a method advance() which reads a line and stores both it and its type. This makes the code more regular and makes it possible to peek ahead without consuming.
author Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com>
date Thu, 08 Dec 2022 15:59:17 +0100 (2022-12-08)
parents 2ded26c5a679
children b4e968e5bd74
line wrap: on
line diff
--- a/src/main/java/org/monetdb/mcl/io/BufferedMCLReader.java
+++ b/src/main/java/org/monetdb/mcl/io/BufferedMCLReader.java
@@ -40,9 +40,10 @@ import java.io.UnsupportedEncodingExcept
  * @see org.monetdb.mcl.net.MapiSocket
  * @see org.monetdb.mcl.io.BufferedMCLWriter
  */
-public final class BufferedMCLReader extends BufferedReader {
+public final class BufferedMCLReader /* extends BufferedReader */ {
 
-	/** The type of the last line read */
+	private final BufferedReader inner;
+	private String current = null;
 	private LineType lineType = LineType.UNKNOWN;
 
 	/**
@@ -52,7 +53,7 @@ public final class BufferedMCLReader ext
 	 * @param in A Reader
 	 */
 	public BufferedMCLReader(final Reader in) {
-		super(in);
+		inner = new BufferedReader(in);
 	}
 
 	/**
@@ -66,47 +67,37 @@ public final class BufferedMCLReader ext
 	public BufferedMCLReader(final InputStream in, final String enc)
 		throws UnsupportedEncodingException
 	{
-		super(new java.io.InputStreamReader(in, enc));
+		this(new java.io.InputStreamReader(in, enc));
+	}
+
+	public void advance() throws IOException {
+		if (lineType == LineType.PROMPT)
+			return;
+
+		current = inner.readLine();
+		lineType = LineType.classify(current);
+		if (lineType == LineType.ERROR && current != null && !current.matches("^![0-9A-Z]{5}!.+")) {
+			current = "!22000!" + current.substring(1);
+		}
 	}
 
 	/**
-	 * Read a line of text.  A line is considered to be terminated by
-	 * any one of a line feed ('\n'), a carriage return ('\r'), or a
-	 * carriage return followed immediately by a linefeed.  Before this
-	 * method returns, it sets the linetype to any of the in MCL
-	 * recognised line types.
-	 *
-	 * Warning: until the server properly prefixes all of its error
-	 * messages with SQLSTATE codes, this method prefixes all errors it
-	 * sees without sqlstate with the generic data exception code (22000).
-	 *
-	 * @return A String containing the contents of the line, not
-	 *         including any line-termination characters, or null if the
-	 *         end of the stream has been reached
-	 * @throws IOException If an I/O error occurs
+	 * Resets the linetype to UNKNOWN.
 	 */
-	@Override
-	public String readLine() throws IOException {
-		String r = super.readLine();
-		setLineType(r);
-		if (lineType == LineType.ERROR && r != null && !r.matches("^![0-9A-Z]{5}!.+")) {
-			r = "!22000!" + r.substring(1);
-		}
-		return r;
+	public void resetLineType() {
+		lineType = LineType.UNKNOWN;
 	}
 
 	/**
-	 * Sets the linetype to the type of the string given.  If the string
-	 * is null, lineType is set to UNKNOWN.
-	 *
-	 * @param line the string to examine
+	 * Return the current line, or null if we're at the end or before the beginning.
+	 * @return the current line or null
 	 */
-	public void setLineType(final String line) {
-		lineType = LineType.classify(line);
+	public String getLine() {
+		return current;
 	}
 
 	/**
-	 * getLineType returns the type of the last line read.
+	 * getLineType returns the type of the current line.
 	 *
 	 * @return Linetype representing the kind of line this is, one of the
 	 *         following enums: UNKNOWN, HEADER, ERROR, RESULT,
@@ -117,35 +108,52 @@ public final class BufferedMCLReader ext
 	}
 
 	/**
-	 * Reads up till the MonetDB prompt, indicating the server is ready
-	 * for a new command.  All read data is discarded.  If the last line
-	 * read by readLine() was a prompt, this method will immediately return.
-	 *
-	 * If there are errors present in the lines that are read, then they
-	 * are put in one string and returned <b>after</b> the prompt has
-	 * been found. If no errors are present, null will be returned.
+	 * Discard the remainder of the response but collect any further error messages.
 	 *
 	 * @return a string containing error messages, or null if there aren't any
 	 * @throws IOException if an IO exception occurs while talking to the server
 	 *
 	 * TODO(Wouter): should probably not have to be synchronized.
 	 */
-	final public synchronized String waitForPrompt() throws IOException {
-		StringBuilder errmsgs = null;
-		String tmp;
+
+
+	final public synchronized String discardRemainder() throws IOException {
+		return discard(null);
+	}
+
+	final public synchronized String discardRemainder(String error) throws IOException {
+		final StringBuilder sb;
 
+		if (error != null) {
+			sb = makeErrorBuffer();
+			sb.append(error);
+		} else {
+			sb = null;
+		}
+		return discard(sb);
+	}
+
+	final synchronized String discard(StringBuilder errmsgs) throws IOException {
 		while (lineType != LineType.PROMPT) {
-			tmp = readLine();
-			if (tmp == null)
+			advance();
+			if (getLine() == null)
 				throw new IOException("Connection to server lost!");
-			if (lineType == LineType.ERROR) {
+			if (getLineType() == LineType.ERROR) {
 				if (errmsgs == null)
 					errmsgs = new StringBuilder(128);
-				errmsgs.append('\n').append(tmp.substring(1));
+				errmsgs.append('\n').append(getLine().substring(1));
 			}
 		}
 		if (errmsgs == null)
 			return null;
 		return errmsgs.toString().trim();
 	}
+
+	private final StringBuilder makeErrorBuffer() {
+		return new StringBuilder(128);
+	}
+
+	public void close() throws IOException {
+		inner.close();
+	}
 }