Mercurial > hg > monetdb-java
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 <- 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 & 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 } |