changeset 576:095e896f9d7a onclient

Updated comments. Improved code. Added final keywords
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Wed, 06 Oct 2021 22:48:11 +0200 (2021-10-06)
parents 08c9918177b2
children 6ab9168ef8e1
files src/main/java/org/monetdb/jdbc/MonetConnection.java src/main/java/org/monetdb/mcl/net/MapiSocket.java src/main/java/org/monetdb/util/FileTransferHandler.java
diffstat 3 files changed, 93 insertions(+), 91 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/monetdb/jdbc/MonetConnection.java
+++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java
@@ -68,7 +68,7 @@ import org.monetdb.mcl.parser.StartOfHea
  *
  * @author Fabian Groffen
  * @author Martin van Dinther
- * @version 1.6
+ * @version 1.7
  */
 public class MonetConnection
 	extends MonetWrapper
@@ -1238,7 +1238,6 @@ public class MonetConnection
 		throw newSQLFeatureNotSupportedException("createArrayOf");
 	}
 
-
 	/**
 	 * Constructs an object that implements the Clob interface. The
 	 * object returned initially contains no data. The setAsciiStream,
@@ -1674,8 +1673,9 @@ public class MonetConnection
 
 	//== internal helper methods which do not belong to the JDBC interface
 
-	/** Handlers for ON CLIENT requests */
+	/** Handler for COPY ... INTO ... FROM 'data-file-name' ON CLIENT requests */
 	private UploadHandler uploadHandler;
+	/** Handler for COPY ... INTO 'data-file-name' ON CLIENT requests */
 	private DownloadHandler downloadHandler;
 
 	/**
@@ -1683,7 +1683,7 @@ public class MonetConnection
 	 *
 	 * @param uploadHandler the handler to register, or null to deregister
 	 */
-	public void setUploadHandler(UploadHandler uploadHandler) {
+	public void setUploadHandler(final UploadHandler uploadHandler) {
 		this.uploadHandler = uploadHandler;
 	}
 
@@ -1693,12 +1693,13 @@ public class MonetConnection
 	public UploadHandler getUploadHandler() {
 		return uploadHandler;
 	}
+
 	/**
 	 * Registers a {@link DownloadHandler} to support for example COPY select_result INTO 'data.csv' ON CLIENT
 	 *
 	 * @param downloadHandler the handler to register, or null to deregister
 	 */
-	public void setDownloadHandler(DownloadHandler downloadHandler) {
+	public void setDownloadHandler(final DownloadHandler downloadHandler) {
 		this.downloadHandler = downloadHandler;
 	}
 
@@ -3020,8 +3021,7 @@ public class MonetConnection
 					// }}} set reply size
 
 					// send query to the server
-					String queryLine = templ[0] + query + templ[1];
-					out.writeLine(queryLine);
+					out.writeLine(templ[0] + query + templ[1]);
 
 					// go for new results
 					String tmpLine = in.readLine();
@@ -3210,9 +3210,9 @@ public class MonetConnection
 	}
 	// }}}
 
-	private String handleTransfer(String transferCommand) throws IOException {
+	private String handleTransfer(final String transferCommand) throws IOException {
 		if (transferCommand.startsWith("r ")) {
-			String[] parts = transferCommand.split(" ", 3);
+			final String[] parts = transferCommand.split(" ", 3);
 			if (parts.length == 3) {
 				final long offset;
 				try {
@@ -3230,19 +3230,18 @@ public class MonetConnection
 		return "JDBC does not support this file transfer yet: " + transferCommand;
 	}
 
-	private String handleUpload(String path, boolean textMode, long offset) throws IOException {
+	private String handleUpload(final String path, final boolean textMode, final long offset) throws IOException {
 		if (uploadHandler == null) {
 			return "No file upload handler has been registered with the JDBC driver";
 		}
 
-		long linesToSkip = offset >= 1 ? offset - 1 : 0;
-		Upload handle = new Upload(server, uploadHandler::uploadCancelled);
-		boolean wasFaking = server.setInsertFakePrompts(false);
+		final long linesToSkip = offset >= 1 ? offset - 1 : 0;
+		final Upload handle = new Upload(server, uploadHandler::uploadCancelled);
+		final boolean wasFaking = server.setInsertFakePrompts(false);
 		try {
 			uploadHandler.handleUpload(handle, path, textMode, linesToSkip);
 			if (!handle.hasBeenUsed()) {
-				String message = "Call to " + uploadHandler.getClass().getCanonicalName() + ".handleUpload for path '" + path + "' sent neither data nor an error message";
-				throw new IOException(message);
+				throw new IOException("Call to " + uploadHandler.getClass().getCanonicalName() + ".handleUpload for path '" + path + "' sent neither data nor an error message");
 			}
 			handle.close();
 		} finally {
@@ -3251,17 +3250,16 @@ public class MonetConnection
 		return handle.getError();
 	}
 
-	private String handleDownload(String path) throws IOException {
+	private String handleDownload(final String path) throws IOException {
 		if (downloadHandler == null) {
 			return "No file download handler has been registered with the JDBC driver";
 		}
 
-		Download handle = new Download(server);
+		final Download handle = new Download(server);
 		try {
 			downloadHandler.handleDownload(handle, path, true);
 			if (!handle.hasBeenUsed()) {
-				String message = "Call to " + downloadHandler.getClass().getSimpleName() + ".handleDownload sent neither data nor error";
-				handle.sendError(message);
+				handle.sendError("Call to " + downloadHandler.getClass().getSimpleName() + ".handleDownload sent neither data nor error");
 			}
 		} finally {
 			handle.close();
@@ -3270,9 +3268,11 @@ public class MonetConnection
 	}
 
 	/**
-	 * Callback for sending files for COPY ON CLIENT
+	 * Callback for sending files for COPY INTO "table" FROM 'file-name' ON CLIENT commands
 	 *
 	 * To be registered with {@link MonetConnection#setUploadHandler(UploadHandler)}
+	 *
+	 * An example implementation can be found at ../util/FileTransferHandler.java
 	 */
 
 	public interface UploadHandler {
@@ -3300,9 +3300,11 @@ public class MonetConnection
 	}
 
 	/**
-	 * Callback for receiving files with COPY ON CLIENT
+	 * Callback for receiving files from COPY .. INTO 'file-name' ON CLIENT commands
 	 *
 	 * To be registered with {@link MonetConnection#setDownloadHandler(DownloadHandler)}
+	 *
+	 * An example implementation can be found at ../util/FileTransferHandler.java
 	 */
 	public interface DownloadHandler {
 		/**
@@ -3344,7 +3346,7 @@ public class MonetConnection
 		 * {@link IOException} but this will terminate the connection.
 		 * @param errorMessage error message to send
 		 */
-		public void sendError(String errorMessage) throws IOException {
+		public void sendError(final String errorMessage) throws IOException {
 			if (error != null) {
 				throw new IOException("another error has already been sent: " + error);
 			}
@@ -3355,7 +3357,7 @@ public class MonetConnection
 		 * After every {@code chunkSize} bytes, the server gets the opportunity to
 		 * terminate the upload.
 		 */
-		public void setChunkSize(int chunkSize) {
+		public void setChunkSize(final int chunkSize) {
 			this.customChunkSize = chunkSize;
 		}
 
@@ -3370,7 +3372,7 @@ public class MonetConnection
 			}
 			if (print == null) {
 				try {
-					MapiSocket.UploadStream up = customChunkSize >= 0 ? server.uploadStream(customChunkSize) : server.uploadStream();
+					final MapiSocket.UploadStream up = customChunkSize >= 0 ? server.uploadStream(customChunkSize) : server.uploadStream();
 					up.setCancellationCallback(cancellationCallback);
 					print = new PrintStream(up, false, "UTF-8");
 					up.write('\n');
@@ -3400,9 +3402,9 @@ public class MonetConnection
 		 *
 		 * For text mode uploads, the data MUST be validly UTF-8 encoded.
 		 */
-		public void uploadFrom(InputStream inputStream) throws IOException {
-			OutputStream s = getStream();
-			byte[] buffer = new byte[64 * 1024];
+		public void uploadFrom(final InputStream inputStream) throws IOException {
+			final OutputStream s = getStream();
+			final byte[] buffer = new byte[64 * 1024];
 			while (true) {
 				int nread = inputStream.read(buffer);
 				if (nread < 0) {
@@ -3418,7 +3420,7 @@ public class MonetConnection
 		 * @param linesToSkip start uploading at line {@code offset}. Value 0 and 1
 		 * both mean upload the whole file, value 2 means skip the first line, etc.q
 		 */
-		public void uploadFrom(BufferedReader reader, long linesToSkip) throws IOException {
+		public void uploadFrom(final BufferedReader reader, final long linesToSkip) throws IOException {
 			for (int i = 0; i < linesToSkip; i++) {
 				String line = reader.readLine();
 				if (line == null) {
@@ -3429,15 +3431,14 @@ public class MonetConnection
 			uploadFrom(reader);
 		}
 
-
 		/**
 		 * Read data from the given buffered reader and send it to the server
 		 * @param reader reader to read from
 		 */
-		public void uploadFrom(Reader reader) throws IOException {
-			OutputStream s = getStream();
-			OutputStreamWriter writer = new OutputStreamWriter(s, StandardCharsets.UTF_8);
-			char[] buffer = new char[64 * 1024];
+		public void uploadFrom(final Reader reader) throws IOException {
+			final OutputStream s = getStream();
+			final OutputStreamWriter writer = new OutputStreamWriter(s, StandardCharsets.UTF_8);
+			final char[] buffer = new char[64 * 1024];
 			while (true) {
 				int nread = reader.read(buffer, 0, buffer.length);
 				if (nread < 0) {
@@ -3448,9 +3449,13 @@ public class MonetConnection
 			}
 		}
 
+		/**
+		 * Close opened {@link PrintStream}.
+		 */
 		public void close() {
 			if (print != null) {
 				print.close();
+				print = null;
 			}
 		}
 	}
@@ -3463,8 +3468,6 @@ public class MonetConnection
 		private MapiSocket.DownloadStream stream = null;
 		private String error = null;
 
-		boolean closed = false;
-
 		Download(MapiSocket server) {
 			this.server = server;
 		}
@@ -3508,13 +3511,14 @@ public class MonetConnection
 		/**
 		 * Write the data from the server to the given {@link OutputStream}.
 		 */
-		public void downloadTo(OutputStream stream) throws IOException {
-			InputStream s = getStream();
-			byte[] buffer = new byte[65536];
+		public void downloadTo(final OutputStream stream) throws IOException {
+			final InputStream s = getStream();
+			final byte[] buffer = new byte[65536];
 			while (true) {
 				int nread = s.read(buffer);
-				if (nread < 0)
+				if (nread < 0) {
 					break;
+				}
 				stream.write(buffer, 0, nread);
 			}
 		}
@@ -3522,7 +3526,6 @@ public class MonetConnection
 		/**
 		 * @return  true if data has been received or an error has been sent.
 		 */
-
 		public boolean hasBeenUsed() {
 			return error != null || stream != null;
 		}
@@ -3530,18 +3533,22 @@ public class MonetConnection
 		/**
 		 * @return the error that was sent, if any
 		 */
-
 		public String getError() {
 			return error;
 		}
-		public void close() throws IOException {
-			if (closed) {
-				return;
+
+		/**
+		 * Close opened stream.
+		 */
+		public void close() {
+			if (stream != null) {
+				try {
+					stream.close();
+					stream = null;
+				} catch (IOException e) {
+					/* ignore close error */
+				}
 			}
-			if (stream != null) {
-				stream.close();
-			}
-			closed = true;
 		}
 	}
 }
--- a/src/main/java/org/monetdb/mcl/net/MapiSocket.java
+++ b/src/main/java/org/monetdb/mcl/net/MapiSocket.java
@@ -81,7 +81,7 @@ import org.monetdb.mcl.parser.MCLParseEx
  * geared towards the format of the data.
  *
  * @author Fabian Groffen
- * @version 4.1
+ * @version 4.2
  * @see org.monetdb.mcl.io.BufferedMCLReader
  * @see org.monetdb.mcl.io.BufferedMCLWriter
  */
@@ -431,6 +431,7 @@ public class MapiSocket {	/* cannot (yet
 	 * @param language the language to use
 	 * @param database the database to connect to
 	 * @param hash the hash method(s) to use, or NULL for all supported hashes
+	 * @return the response string for the server
 	 */
 	private String getChallengeResponse(
 			final String chalstr,
@@ -549,10 +550,9 @@ public class MapiSocket {	/* cannot (yet
 						+ username + ":"
 						+ pwhash + ":"
 						+ language + ":"
-						+ (database == null ? "" : database) + ":";
-				response += "FILETRANS:";
+						+ (database == null ? "" : database) + ":"
+						+ "FILETRANS:";	 // this capability is added in monetdb-jdbc-3.2.jre8.jar
 				if (chaltok.length > 6) {
-
 					// if supported, send handshake options
 					for (String part : chaltok[6].split(",")) {
 						if (part.startsWith("sql=") && handshakeOptions != null) {
@@ -568,7 +568,6 @@ public class MapiSocket {	/* cannot (yet
 					}
 					// this ':' delimits the handshake options field.
 					response += ":";
-
 				}
 				return response;
 			default:
@@ -599,7 +598,6 @@ public class MapiSocket {	/* cannot (yet
 			: (char) ('0' + n);
 	}
 
-
 	/**
 	 * Returns an InputStream that reads from this open connection on
 	 * the MapiSocket.
@@ -735,6 +733,7 @@ public class MapiSocket {	/* cannot (yet
 		return fromMonet.setInsertFakePrompts(b);
 	}
 
+
 	/**
 	 * Inner class that is used to write data on a normal stream as a
 	 * blocked stream.  A call to the flush() method will write a
@@ -1218,10 +1217,11 @@ public class MapiSocket {	/* cannot (yet
 		super.finalize();
 	}
 
+
 	/**
 	 * Stream of data sent to the server
-	 * 
- 	 * Building block for {@link org.monetdb.jdbc.MonetConnection.UploadHandler}.
+	 *
+	 * Building block for {@link org.monetdb.jdbc.MonetConnection.UploadHandler}.
 	 *
 	 * An UploadStream has a chunk size. Every chunk size bytes, the server gets
 	 * the opportunity to abort the upload.
@@ -1236,7 +1236,7 @@ public class MapiSocket {	/* cannot (yet
 		private Runnable cancellationCallback = null;
 
 		/** Create an UploadStream with the given chunk size */
-		UploadStream(int chunkSize) {
+		UploadStream(final int chunkSize) {
 			super(toMonet);
 			if (chunkSize <= 0) {
 				throw new IllegalArgumentException("chunk size must be positive");
@@ -1255,12 +1255,12 @@ public class MapiSocket {	/* cannot (yet
 
 		/** Set a callback to be invoked if the server cancels the upload
 		 */
-		public void setCancellationCallback(Runnable cancellationCallback) {
+		public void setCancellationCallback(final Runnable cancellationCallback) {
 			this.cancellationCallback = cancellationCallback;
 		}
 
 		@Override
-		public void write(int b) throws IOException {
+		public void write(final int b) throws IOException {
 			if (serverCancelled) {
 				// We have already thrown an exception and apparently that has been ignored.
 				// Probably because they're calling print methods instead of write.
@@ -1273,12 +1273,12 @@ public class MapiSocket {	/* cannot (yet
 		}
 
 		@Override
-		public void write(byte[] b) throws IOException {
+		public void write(final byte[] b) throws IOException {
 			write(b, 0, b.length);
 		}
 
 		@Override
-		public void write(byte[] b, int off, int len) throws IOException {
+		public void write(final byte[] b, int off, int len) throws IOException {
 			if (serverCancelled) {
 				// We have already thrown an exception and apparently that has been ignored.
 				// Probably because they're calling print methods instead of write.
@@ -1320,17 +1320,17 @@ public class MapiSocket {	/* cannot (yet
 			}
 			// send empty block
 			out.flush();
-			LineType acknowledgement = readPrompt();
+			final LineType acknowledgement = readPrompt();
 			if (acknowledgement != LineType.FILETRANSFER) {
 				throw new IOException("Expected server to acknowledge end of file");
 			}
 		}
 
-		private void closeAfterServerCancelled() throws IOException {
+		private void closeAfterServerCancelled() {
 			// nothing to do here, we have already read the error prompt.
 		}
 
-		private void wrote(int i) {
+		private void wrote(final int i) {
 			chunkLeft -= i;
 		}
 
@@ -1344,7 +1344,7 @@ public class MapiSocket {	/* cannot (yet
 		private void flushAndReadPrompt() throws IOException {
 			out.flush();
 			chunkLeft = chunkSize;
-			LineType lineType = readPrompt();
+			final LineType lineType = readPrompt();
 			switch (lineType) {
 				case MORE:
 					return;
@@ -1362,22 +1362,21 @@ public class MapiSocket {	/* cannot (yet
 		}
 
 		private LineType readPrompt() throws IOException {
-			int nread = fromMonet.read(promptBuffer);
+			final int nread = fromMonet.read(promptBuffer);
 			if (nread != promptBuffer.length || promptBuffer[promptBuffer.length - 1] != '\n') {
 				throw new IOException("server return incomplete prompt");
 			}
-			LineType lineType = LineType.classify(promptBuffer);
-			return lineType;
+			return LineType.classify(promptBuffer);
 		}
 	}
 
+
 	/**
 	 * Stream of data received from the server
-	 * 
- 	 * Building block for {@link org.monetdb.jdbc.MonetConnection.DownloadHandler}.
+	 *
+	 * Building block for {@link org.monetdb.jdbc.MonetConnection.DownloadHandler}.
 	 */
 	public static class DownloadStream extends InputStream {
-
 		private final BlockInputStream.Raw rawIn;
 		private final OutputStream out;
 		private boolean endBlockSeen = false;
@@ -1391,7 +1390,7 @@ public class MapiSocket {	/* cannot (yet
 		void nextBlock() throws IOException {
 			if (endBlockSeen || closed)
 				return;
-			int ret = rawIn.readBlock();
+			final int ret = rawIn.readBlock();
 			if (ret < 0 || rawIn.wasEndBlock()) {
 				endBlockSeen = true;
 			}
@@ -1414,8 +1413,8 @@ public class MapiSocket {	/* cannot (yet
 
 		@Override
 		public int read() throws IOException {
-			byte[] buf = { 0 };
-			int nread = read(buf, 0, 1);
+			final byte[] buf = { 0 };
+			final int nread = read(buf, 0, 1);
 			if (nread == 1)
 				return buf[0];
 			else
@@ -1423,8 +1422,8 @@ public class MapiSocket {	/* cannot (yet
 		}
 
 		@Override
-		public int read(byte[] b, int off, int len) throws IOException {
-			int origOff = off;
+		public int read(final byte[] b, int off, int len) throws IOException {
+			final int origOff = off;
 			while (len > 0) {
 				int chunk = Integer.min(len, rawIn.getLength() - rawIn.getPosition());
 				if (chunk > 0) {
--- a/src/main/java/org/monetdb/util/FileTransferHandler.java
+++ b/src/main/java/org/monetdb/util/FileTransferHandler.java
@@ -10,9 +10,7 @@ package org.monetdb.util;
 
 import org.monetdb.jdbc.MonetConnection;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.FileSystems;
@@ -21,7 +19,7 @@ import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 
 /**
- * Sample implement of ON CLIENT handling
+ * Sample implementation of COPY ... INTO 'file-name' ON CLIENT handling
  *
  * Can be registered with {@link MonetConnection#setUploadHandler(MonetConnection.UploadHandler)}
  * and {@link MonetConnection#setDownloadHandler(MonetConnection.DownloadHandler)}.
@@ -37,7 +35,7 @@ public class FileTransferHandler impleme
 	 * @param dir directory to read and write files from
 	 * @param utf8Encoded set this to true if all files in the directory are known to be utf-8 encoded.
 	 */
-	public FileTransferHandler(Path dir, boolean utf8Encoded) {
+	public FileTransferHandler(final Path dir, final boolean utf8Encoded) {
 		root = dir.toAbsolutePath().normalize();
 		this.utf8Encoded = utf8Encoded;
 	}
@@ -48,12 +46,12 @@ public class FileTransferHandler impleme
 	 * @param dir directory to read and write files from
 	 * @param utf8Encoded set this to true if all files in the directory are known to be utf-8 encoded.
 	 */
-	public FileTransferHandler(String dir, boolean utf8Encoded) {
+	public FileTransferHandler(final String dir, final boolean utf8Encoded) {
 		this(FileSystems.getDefault().getPath(dir), utf8Encoded);
 	}
 
-	public void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, long linesToSkip) throws IOException {
-		Path path = root.resolve(name).normalize();
+	public void handleUpload(final MonetConnection.Upload handle, final String name, final boolean textMode, final long linesToSkip) throws IOException {
+		final Path path = root.resolve(name).normalize();
 		if (!path.startsWith(root)) {
 			handle.sendError("File is not in upload directory");
 			return;
@@ -63,16 +61,15 @@ public class FileTransferHandler impleme
 			return;
 		}
 		if (textMode && (linesToSkip > 0 || !utf8Encoded)) {
-			Charset encoding = utf8Encoded ? StandardCharsets.UTF_8 : Charset.defaultCharset();
-			BufferedReader reader = Files.newBufferedReader(path, encoding);
-			handle.uploadFrom(reader, linesToSkip);
+			final Charset encoding = utf8Encoded ? StandardCharsets.UTF_8 : Charset.defaultCharset();
+			handle.uploadFrom(Files.newBufferedReader(path, encoding), linesToSkip);
 		} else {
 			handle.uploadFrom(Files.newInputStream(path));
 		}
 	}
 
-	public void handleDownload(MonetConnection.Download handle, String name, boolean textMode) throws IOException {
-		Path path = root.resolve(name).normalize();
+	public void handleDownload(final MonetConnection.Download handle, final String name, final boolean textMode) throws IOException {
+		final Path path = root.resolve(name).normalize();
 		if (!path.startsWith(root)) {
 			handle.sendError("File is not in download directory");
 			return;
@@ -81,7 +78,6 @@ public class FileTransferHandler impleme
 			handle.sendError("File already exists: " + name);
 			return;
 		}
-		OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE_NEW);
-		handle.downloadTo(outputStream);
+		handle.downloadTo(Files.newOutputStream(path, StandardOpenOption.CREATE_NEW));
 	}
-}
\ No newline at end of file
+}