Mercurial > hg > monetdb-java
comparison 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 |
comparison
equal
deleted
inserted
replaced
699:0ff364f569a1 | 700:940e266eeccd |
---|---|
38 * | 38 * |
39 * @author Fabian Groffen | 39 * @author Fabian Groffen |
40 * @see org.monetdb.mcl.net.MapiSocket | 40 * @see org.monetdb.mcl.net.MapiSocket |
41 * @see org.monetdb.mcl.io.BufferedMCLWriter | 41 * @see org.monetdb.mcl.io.BufferedMCLWriter |
42 */ | 42 */ |
43 public final class BufferedMCLReader extends BufferedReader { | 43 public final class BufferedMCLReader /* extends BufferedReader */ { |
44 | 44 |
45 /** The type of the last line read */ | 45 private final BufferedReader inner; |
46 private String current = null; | |
46 private LineType lineType = LineType.UNKNOWN; | 47 private LineType lineType = LineType.UNKNOWN; |
47 | 48 |
48 /** | 49 /** |
49 * Create a buffering character-input stream that uses a | 50 * Create a buffering character-input stream that uses a |
50 * default-sized input buffer. | 51 * default-sized input buffer. |
51 * | 52 * |
52 * @param in A Reader | 53 * @param in A Reader |
53 */ | 54 */ |
54 public BufferedMCLReader(final Reader in) { | 55 public BufferedMCLReader(final Reader in) { |
55 super(in); | 56 inner = new BufferedReader(in); |
56 } | 57 } |
57 | 58 |
58 /** | 59 /** |
59 * Create a buffering character-input stream that uses a | 60 * Create a buffering character-input stream that uses a |
60 * default-sized input buffer, from an InputStream. | 61 * default-sized input buffer, from an InputStream. |
64 * @throws UnsupportedEncodingException If encoding is not supported | 65 * @throws UnsupportedEncodingException If encoding is not supported |
65 */ | 66 */ |
66 public BufferedMCLReader(final InputStream in, final String enc) | 67 public BufferedMCLReader(final InputStream in, final String enc) |
67 throws UnsupportedEncodingException | 68 throws UnsupportedEncodingException |
68 { | 69 { |
69 super(new java.io.InputStreamReader(in, enc)); | 70 this(new java.io.InputStreamReader(in, enc)); |
71 } | |
72 | |
73 public void advance() throws IOException { | |
74 if (lineType == LineType.PROMPT) | |
75 return; | |
76 | |
77 current = inner.readLine(); | |
78 lineType = LineType.classify(current); | |
79 if (lineType == LineType.ERROR && current != null && !current.matches("^![0-9A-Z]{5}!.+")) { | |
80 current = "!22000!" + current.substring(1); | |
81 } | |
70 } | 82 } |
71 | 83 |
72 /** | 84 /** |
73 * Read a line of text. A line is considered to be terminated by | 85 * Resets the linetype to UNKNOWN. |
74 * any one of a line feed ('\n'), a carriage return ('\r'), or a | |
75 * carriage return followed immediately by a linefeed. Before this | |
76 * method returns, it sets the linetype to any of the in MCL | |
77 * recognised line types. | |
78 * | |
79 * Warning: until the server properly prefixes all of its error | |
80 * messages with SQLSTATE codes, this method prefixes all errors it | |
81 * sees without sqlstate with the generic data exception code (22000). | |
82 * | |
83 * @return A String containing the contents of the line, not | |
84 * including any line-termination characters, or null if the | |
85 * end of the stream has been reached | |
86 * @throws IOException If an I/O error occurs | |
87 */ | 86 */ |
88 @Override | 87 public void resetLineType() { |
89 public String readLine() throws IOException { | 88 lineType = LineType.UNKNOWN; |
90 String r = super.readLine(); | |
91 setLineType(r); | |
92 if (lineType == LineType.ERROR && r != null && !r.matches("^![0-9A-Z]{5}!.+")) { | |
93 r = "!22000!" + r.substring(1); | |
94 } | |
95 return r; | |
96 } | 89 } |
97 | 90 |
98 /** | 91 /** |
99 * Sets the linetype to the type of the string given. If the string | 92 * Return the current line, or null if we're at the end or before the beginning. |
100 * is null, lineType is set to UNKNOWN. | 93 * @return the current line or null |
101 * | |
102 * @param line the string to examine | |
103 */ | 94 */ |
104 public void setLineType(final String line) { | 95 public String getLine() { |
105 lineType = LineType.classify(line); | 96 return current; |
106 } | 97 } |
107 | 98 |
108 /** | 99 /** |
109 * getLineType returns the type of the last line read. | 100 * getLineType returns the type of the current line. |
110 * | 101 * |
111 * @return Linetype representing the kind of line this is, one of the | 102 * @return Linetype representing the kind of line this is, one of the |
112 * following enums: UNKNOWN, HEADER, ERROR, RESULT, | 103 * following enums: UNKNOWN, HEADER, ERROR, RESULT, |
113 * PROMPT, MORE, FILETRANSFER, SOHEADER, REDIRECT, INFO | 104 * PROMPT, MORE, FILETRANSFER, SOHEADER, REDIRECT, INFO |
114 */ | 105 */ |
115 public LineType getLineType() { | 106 public LineType getLineType() { |
116 return lineType; | 107 return lineType; |
117 } | 108 } |
118 | 109 |
119 /** | 110 /** |
120 * Reads up till the MonetDB prompt, indicating the server is ready | 111 * Discard the remainder of the response but collect any further error messages. |
121 * for a new command. All read data is discarded. If the last line | |
122 * read by readLine() was a prompt, this method will immediately return. | |
123 * | |
124 * If there are errors present in the lines that are read, then they | |
125 * are put in one string and returned <b>after</b> the prompt has | |
126 * been found. If no errors are present, null will be returned. | |
127 * | 112 * |
128 * @return a string containing error messages, or null if there aren't any | 113 * @return a string containing error messages, or null if there aren't any |
129 * @throws IOException if an IO exception occurs while talking to the server | 114 * @throws IOException if an IO exception occurs while talking to the server |
130 * | 115 * |
131 * TODO(Wouter): should probably not have to be synchronized. | 116 * TODO(Wouter): should probably not have to be synchronized. |
132 */ | 117 */ |
133 final public synchronized String waitForPrompt() throws IOException { | |
134 StringBuilder errmsgs = null; | |
135 String tmp; | |
136 | 118 |
119 | |
120 final public synchronized String discardRemainder() throws IOException { | |
121 return discard(null); | |
122 } | |
123 | |
124 final public synchronized String discardRemainder(String error) throws IOException { | |
125 final StringBuilder sb; | |
126 | |
127 if (error != null) { | |
128 sb = makeErrorBuffer(); | |
129 sb.append(error); | |
130 } else { | |
131 sb = null; | |
132 } | |
133 return discard(sb); | |
134 } | |
135 | |
136 final synchronized String discard(StringBuilder errmsgs) throws IOException { | |
137 while (lineType != LineType.PROMPT) { | 137 while (lineType != LineType.PROMPT) { |
138 tmp = readLine(); | 138 advance(); |
139 if (tmp == null) | 139 if (getLine() == null) |
140 throw new IOException("Connection to server lost!"); | 140 throw new IOException("Connection to server lost!"); |
141 if (lineType == LineType.ERROR) { | 141 if (getLineType() == LineType.ERROR) { |
142 if (errmsgs == null) | 142 if (errmsgs == null) |
143 errmsgs = new StringBuilder(128); | 143 errmsgs = new StringBuilder(128); |
144 errmsgs.append('\n').append(tmp.substring(1)); | 144 errmsgs.append('\n').append(getLine().substring(1)); |
145 } | 145 } |
146 } | 146 } |
147 if (errmsgs == null) | 147 if (errmsgs == null) |
148 return null; | 148 return null; |
149 return errmsgs.toString().trim(); | 149 return errmsgs.toString().trim(); |
150 } | 150 } |
151 | |
152 private final StringBuilder makeErrorBuffer() { | |
153 return new StringBuilder(128); | |
154 } | |
155 | |
156 public void close() throws IOException { | |
157 inner.close(); | |
158 } | |
151 } | 159 } |