📄 monetsocketblockmode.java
字号:
} private int readPos = 0; private boolean lastBlock = false; /** * readLine reads one line terminated by a newline character and * returns it without the newline character. This operation can be * blocking if there is no information available (yet). If a block * is marked as the last one, and the (left over) data does not end * in a newline, it is returned as the last "line" before returning * the prompt. * * @return a string representing the next line from the stream * @throws IOException if reading from the stream fails */ public String readLine() throws IOException { synchronized (fromMonetRaw) { /* * The blocked stream protocol consists of first a two byte * integer indicating the length of the block, then the * block, followed by another length + block. The end of * such sequence is put in the last bit of the length, and * hence this length should be shifted to the right to * obtain the real length value first. * In this implementation we do not detect or use the user * flush as it is not needed to detect for us since the * higher level MAPI protocol defines a prompt which is used * for synchronisation. We simply fetch blocks here as soon * as they are needed to process them line-based. * * The user-flush is a legacy thing now, and we simulate it * to the levels above, by inserting it at the end of each * 'lastBlock'. */ int nl; while ((nl = readBuffer.indexOf("\n", readPos)) == -1) { // not found, fetch us some more data // start reading a new block of data if appropriate if (readState == 0) { if (lastBlock) { if (readPos < readBuffer.length()) { // there is still some stuff, but not // terminated by a \n, send it to the user String line = readBuffer.substring(readPos); setLineType(readBuffer.charAt(readPos), line); // move the cursor position readPos = readBuffer.length(); return(line); } lastBlock = false; // emit a fake prompt message if (debug) logRd("generating prompt"); lineType = PROMPT1; return(""); // we omit putting the prompt in here } // read next two bytes (short) int size = fromMonetRaw.read(blklen); if (size == -1) throw new IOException("End of stream reached"); if (size < 2) throw new AssertionError("Illegal start of block"); // Get the int-value and store it in the readState. // We store having the last block or not, for later // to generate a prompt message. readState = (short)( (blklen[0] & 0xFF) >> 1 | (blklen[1] & 0xFF) << 7 ); lastBlock = (blklen[0] & 0x1) == 1; if (debug) { if (lastBlock) { logRd("final block: " + readState + " bytes"); } else { logRd("new block: " + readState + " bytes"); } } } // 'continue' fetching current block byte[] data = new byte[BLOCK < readState ? BLOCK : readState]; int size = fromMonetRaw.read(data); if (size == -1) throw new IOException("End of stream reached"); // update the state readState -= size; // clean up the buffer readBuffer.delete(0, readPos); readPos = 0; // append the stuff to the buffer; let String do the charset // conversion stuff readBuffer.append(new String(data, 0, size, "UTF-8")); if (debug) { logRd("read chunk: " + size + " bytes, left: " + readState + " bytes"); logRx(new String(data, "UTF-8")); } } // fill line, excluding newline String line = readBuffer.substring(readPos, nl); setLineType(readBuffer.charAt(readPos), line); // move the cursor position readPos = nl + 1; return(line); } } /** * Returns the type of the string given. This method assumes a * non-null string. * * @param first the first char from line * @param line the string to examine * @return the type of the given string */ private void setLineType(char first, String line) { lineType = UNKNOWN; switch (first) { case '!': lineType = ERROR; break; case '&': lineType = SOHEADER; break; case '%': lineType = HEADER; break; case '[': lineType = RESULT; break; case '^': lineType = REDIRECT; break; case '#': lineType = INFO; break; default: if (first == (char)1 && line.length() == 2) { if (line.charAt(1) == (char)1) { /* MAPI PROMPT1 */ lineType = PROMPT1; } else if (line.charAt(1) == (char)2) { /* MAPI PROMPT2 (MORE) */ lineType = PROMPT2; } } break; } } /** * getLineType returns the type of the last line read. * * @return an integer representing the kind of line this is, one of the * following constants: UNKNOWN, HEADER, ERROR, PROMPT, * RESULT, REDIRECT, INFO */ public int getLineType() { return(lineType); } /** * 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. * <br /><br /> * 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. * * @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 */ final public synchronized String waitForPrompt() throws IOException { String ret = "", tmp; while (lineType != PROMPT1) { if ((tmp = readLine()) == null) throw new IOException("Connection to server lost!"); if (lineType == ERROR) ret += "\n" + tmp.substring(1); } return(ret == "" ? null : ret.trim()); } /** * disconnect closes the streams and socket connected to the MonetDB server * if possible. If an error occurs during disconnecting it is ignored. */ public synchronized void disconnect() { try { fromMonetRaw.close(); toMonetRaw.close(); con.close(); if (debug) log.close(); } catch (IOException e) { // ignore it } } /** * Destructor called by garbage collector before destroying this * object tries to disconnect the MonetDB connection if it has not * been disconnected already. */ protected void finalize() throws Throwable { disconnect(); 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 */ 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 */ 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 */ 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 */ void logRd(String message) throws IOException { log.write("RD " + System.currentTimeMillis() + ": " + message + "\n"); log.flush(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -