comparison src/main/java/org/monetdb/mcl/io/BufferedMCLReader.java @ 391:f523727db392

Moved Java classes from packages starting with nl.cwi.monetdb.* to package org.monetdb.* This naming complies to the Java Package Naming convention as MonetDB's main website is www.monetdb.org.
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Thu, 12 Nov 2020 22:02:01 +0100 (2020-11-12)
parents src/main/java/nl/cwi/monetdb/mcl/io/BufferedMCLReader.java@54137aeb1f92
children bf9f6b6ecf40
comparison
equal deleted inserted replaced
390:6199e0be3c6e 391:f523727db392
1 /*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2020 MonetDB B.V.
7 */
8
9 package org.monetdb.mcl.io;
10
11 import java.io.BufferedReader;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.Reader;
15 import java.io.UnsupportedEncodingException;
16
17 /**
18 * Read text from a character-input stream, buffering characters so as
19 * to provide a means for efficient reading of characters, arrays and
20 * lines. This class is based on the BufferedReader class, and provides
21 * extra functionality useful for MCL.
22 *
23 * The BufferedMCLReader is typically used as layer inbetween an
24 * InputStream and a specific interpreter of the data.
25 * <pre>
26 * / Response
27 * BufferedMCLReader ---o &lt;- Tuple
28 * \ DataBlock
29 * </pre>
30 * Because the BufferedMCLReader provides an efficient way to access the
31 * data from the stream in a linewise fashion, whereby each line is
32 * identified as a certain type, consumers can easily decide how to
33 * parse each retrieved line. The line parsers from
34 * org.monetdb.mcl.parser are well suited to work with the lines
35 * outputted by the BufferedMCLReader.
36 * This class is client-oriented, as it doesn't take into account the
37 * messages as the server receives them.
38 *
39 * @author Fabian Groffen
40 * @see org.monetdb.mcl.net.MapiSocket
41 * @see org.monetdb.mcl.io.BufferedMCLWriter
42 */
43 public final class BufferedMCLReader extends BufferedReader {
44 /** "there is currently no line", or the the type is unknown is represented by UNKNOWN */
45 public final static int UNKNOWN = 0;
46 /** a line starting with ! indicates ERROR */
47 public final static int ERROR = '!';
48 /** a line starting with % indicates HEADER */
49 public final static int HEADER = '%';
50 /** a line starting with [ indicates RESULT */
51 public final static int RESULT = '[';
52 /** a line which matches the pattern of prompt1 is a PROMPT */
53 public final static int PROMPT = '.';
54 /** a line which matches the pattern of prompt2 is a MORE */
55 public final static int MORE = ',';
56 /** a line starting with &amp; indicates the start of a header block */
57 public final static int SOHEADER = '&';
58 /** a line starting with ^ indicates REDIRECT */
59 public final static int REDIRECT = '^';
60 /** a line starting with # indicates INFO */
61 public final static int INFO = '#';
62
63 /** The type of the last line read */
64 private int lineType = UNKNOWN;
65
66 /**
67 * Create a buffering character-input stream that uses a
68 * default-sized input buffer.
69 *
70 * @param in A Reader
71 */
72 public BufferedMCLReader(final Reader in) {
73 super(in);
74 }
75
76 /**
77 * Create a buffering character-input stream that uses a
78 * default-sized input buffer, from an InputStream.
79 *
80 * @param in An InputStream
81 * @param enc Encoding
82 * @throws UnsupportedEncodingException If encoding is not supported
83 */
84 public BufferedMCLReader(final InputStream in, final String enc)
85 throws UnsupportedEncodingException
86 {
87 super(new java.io.InputStreamReader(in, enc));
88 }
89
90 /**
91 * Read a line of text. A line is considered to be terminated by
92 * any one of a line feed ('\n'), a carriage return ('\r'), or a
93 * carriage return followed immediately by a linefeed. Before this
94 * method returns, it sets the linetype to any of the in MCL
95 * recognised line types.
96 *
97 * Warning: until the server properly prefixes all of its error
98 * messages with SQLSTATE codes, this method prefixes all errors it
99 * sees without sqlstate with the generic data exception code (22000).
100 *
101 * @return A String containing the contents of the line, not
102 * including any line-termination characters, or null if the
103 * end of the stream has been reached
104 * @throws IOException If an I/O error occurs
105 */
106 @Override
107 public String readLine() throws IOException {
108 String r = super.readLine();
109 setLineType(r);
110 if (lineType == ERROR && r != null && !r.matches("^![0-9A-Z]{5}!.+")) {
111 r = "!22000!" + r.substring(1);
112 }
113 return r;
114 }
115
116 /**
117 * Sets the linetype to the type of the string given. If the string
118 * is null, lineType is set to UNKNOWN.
119 *
120 * @param line the string to examine
121 */
122 public void setLineType(final String line) {
123 if (line == null || line.isEmpty()) {
124 lineType = UNKNOWN;
125 return;
126 }
127 switch (line.charAt(0)) {
128 case '.':
129 lineType = PROMPT;
130 break;
131 case ',':
132 lineType = MORE;
133 break;
134 case '[': /* multi field result */
135 case '=': /* single value result */
136 lineType = RESULT;
137 break;
138 case '%':
139 lineType = HEADER;
140 break;
141 case '&':
142 lineType = SOHEADER;
143 break;
144 case '#':
145 lineType = INFO;
146 break;
147 case '!':
148 lineType = ERROR;
149 break;
150 case '^':
151 lineType = REDIRECT;
152 break;
153 default:
154 lineType = UNKNOWN;
155 }
156 }
157
158 /**
159 * getLineType returns the type of the last line read.
160 *
161 * @return an integer representing the kind of line this is, one of the
162 * following constants: UNKNOWN, HEADER, ERROR, PROMPT, MORE,
163 * RESULT, SOHEADER, REDIRECT, INFO
164 */
165 public int getLineType() {
166 return lineType;
167 }
168
169 /**
170 * Reads up till the MonetDB prompt, indicating the server is ready
171 * for a new command. All read data is discarded. If the last line
172 * read by readLine() was a prompt, this method will immediately return.
173 *
174 * If there are errors present in the lines that are read, then they
175 * are put in one string and returned <b>after</b> the prompt has
176 * been found. If no errors are present, null will be returned.
177 *
178 * @return a string containing error messages, or null if there aren't any
179 * @throws IOException if an IO exception occurs while talking to the server
180 *
181 * TODO(Wouter): should probably not have to be synchronized.
182 */
183 final public synchronized String waitForPrompt() throws IOException {
184 final StringBuilder ret = new StringBuilder(128);
185 String tmp;
186
187 while (lineType != PROMPT) {
188 tmp = readLine();
189 if (tmp == null)
190 throw new IOException("Connection to server lost!");
191 if (lineType == ERROR)
192 ret.append('\n').append(tmp.substring(1));
193 }
194 return ret.length() == 0 ? null : ret.toString().trim();
195 }
196 }