changeset 535:c9d88af06d35 onclient

Javadoc and some minor changes
author Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com>
date Fri, 27 Aug 2021 16:13:54 +0200 (2021-08-27)
parents b437529144f1
children daf6a3b828f9
files src/main/java/org/monetdb/jdbc/MonetConnection.java src/main/java/org/monetdb/jdbc/MonetDownloadHandler.java src/main/java/org/monetdb/jdbc/MonetUploadHandler.java src/main/java/org/monetdb/mcl/io/LineType.java src/main/java/org/monetdb/mcl/net/MapiSocket.java src/main/java/org/monetdb/util/FileTransferHandler.java tests/build.xml
diffstat 7 files changed, 212 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/monetdb/jdbc/MonetConnection.java
+++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java
@@ -152,8 +152,8 @@ public class MonetConnection
 	private DatabaseMetaData dbmd;
 
 	/** Handlers for ON CLIENT requests */
-	private MonetUploadHandler uploader;
-	private MonetDownloadHandler downloader;
+	private MonetUploadHandler uploadHandler;
+	private MonetDownloadHandler downloadHandler;
 
 	/**
 	 * Constructor of a Connection for MonetDB. At this moment the
@@ -1198,34 +1198,34 @@ public class MonetConnection
 	}
 
 	/**
-	 * Registers a MonetUploader to support for example COPY ON CLIENT
+	 * Registers a {@link MonetUploadHandler} to support for example COPY ON CLIENT
 	 *
 	 * @param uploadHandler the handler to register, or null to deregister
 	 */
 	public void setUploadHandler(MonetUploadHandler uploadHandler) {
-		this.uploader = uploadHandler;
+		this.uploadHandler = uploadHandler;
 	}
 
 	/**
-	 * Returns the currently registerered MonetUploader, or null
+	 * Returns the currently registerered {@link MonetUploadHandler}, or null
 	 */
 	public MonetUploadHandler getUploadHandler() {
-		return uploader;
+		return uploadHandler;
 	}
 	/**
-	 * Registers a MonetDownloader to support for example COPY ON CLIENT
+	 * Registers a {@link MonetDownloadHandler} to support for example COPY ON CLIENT
 	 *
 	 * @param downloadHandler the handler to register, or null to deregister
 	 */
 	public void setDownloadHandler(MonetDownloadHandler downloadHandler) {
-		this.downloader = downloadHandler;
+		this.downloadHandler = downloadHandler;
 	}
 
 	/**
-	 * Returns the currently registerered MonetDownloadHandler handler, or null
+	 * Returns the currently registerered {@link MonetDownloadHandler} handler, or null
 	 */
 	public MonetDownloadHandler getDownloadHandler() {
-		return downloader;
+		return downloadHandler;
 	}
 
 	/**
@@ -3227,17 +3227,17 @@ public class MonetConnection
 	}
 
 	private String handleUpload(String path, boolean textMode, int offset) throws IOException {
-		if (uploader == null) {
+		if (uploadHandler == null) {
 			return "No file upload handler has been registered with the JDBC driver";
 		}
 
 		Upload handle = new Upload(server);
 		boolean wasFaking = server.setInsertFakePrompts(false);
 		try {
-			uploader.handleUpload(handle, path, textMode, offset);
+			uploadHandler.handleUpload(handle, path, textMode, offset);
 			if (!handle.hasBeenUsed()) {
 				String message = String.format("Call to %s.handleUpload for path '%s' sent neither data nor an error message",
-						uploader.getClass().getCanonicalName(), path);
+						uploadHandler.getClass().getCanonicalName(), path);
 				throw new IOException(message);
 			}
 			handle.close();
@@ -3248,21 +3248,24 @@ public class MonetConnection
 	}
 
 	private String handleDownload(String path) throws IOException {
-		if (downloader == null) {
+		if (downloadHandler == null) {
 			return "No file download handler has been registered with the JDBC driver";
 		}
 
 		Download handle = new Download(server);
-		downloader.handleDownload(handle, path, true);
+		downloadHandler.handleDownload(handle, path, true);
 		if (!handle.hasBeenUsed()) {
 			String message = String.format("Call to %s.handleDownload for path '%s' sent neither data nor an error message",
-					downloader.getClass().getCanonicalName(), path);
+					downloadHandler.getClass().getCanonicalName(), path);
 			throw new IOException(message);
 		}
 		handle.close();
 		return handle.getError();
 	}
 
+	/**
+	 * Handle passed to {@link MonetUploadHandler} to allow communication with the server
+	 */
 	public static class Upload {
 		private final MapiSocket server;
 		private PrintStream print = null;
@@ -3273,6 +3276,18 @@ public class MonetConnection
 			this.server = server;
 		}
 
+		/**
+		 * Send an error message to the server
+		 *
+		 * The server will generally let the currently executing statement fail
+		 * with this error message. The connection will remain usable. 
+		 *
+		 * This method can only be sent if no data has been sent to the server
+		 * yet. After data has been sent, you can still throw an
+		 * {@link IOException} but this will terminate the connection.
+		 * @param errorMessage
+		 * @throws IOException
+		 */
 		public void sendError(String errorMessage) throws IOException {
 			if (error != null) {
 				throw new IOException("another error has already been sent: " + error);
@@ -3280,10 +3295,22 @@ public class MonetConnection
 			error = errorMessage;
 		}
 
+		/**
+		 * After every {@code chunkSize} bytes, the server gets the opportunity to
+		 * terminate the upload.
+		 * @param chunkSize
+		 */
 		public void setChunkSize(int chunkSize) {
 			this.customChunkSize = chunkSize;
 		}
 
+		/**
+		 * Get a {@link PrintStream} to write data to.
+		 *
+		 * For text mode uploads, the data MUST be validly UTF-8 encoded.
+		 * @return
+		 * @throws IOException
+		 */
 		public PrintStream getStream() throws IOException {
 			if (error != null) {
 				throw new IOException("Cannot send data after an error has been sent");
@@ -3300,14 +3327,29 @@ public class MonetConnection
 			return print;
 		}
 
+		/**
+		 * Returns true if data or an error has been sent.
+		 * @return
+		 */
 		public boolean hasBeenUsed() {
 			return print != null || error != null;
 		}
 
+		/**
+		 * Get the error that was sent, if any
+		 * @return
+		 */
 		public String getError() {
 			return error;
 		}
 
+		/**
+		 * Read from the given input stream and write it to the server.
+		 * 
+		 * For text mode uploads, the data MUST be validly UTF-8 encoded.
+		 * @param inputStream
+		 * @throws IOException
+		 */
 		public void uploadFrom(InputStream inputStream) throws IOException {
 			OutputStream s = getStream();
 			byte[] buffer = new byte[64 * 1024];
@@ -3320,6 +3362,13 @@ public class MonetConnection
 			}
 		}
 
+		/**
+		 * Read data from the given buffered reader and send it to the server
+		 * @param reader reader to read from
+		 * @param offset 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
+		 * @throws IOException
+		 */
 		public void uploadFrom(BufferedReader reader, int offset) throws IOException {
 			// we're 1-based but also accept 0
 			if (offset > 0) {
@@ -3336,6 +3385,12 @@ public class MonetConnection
 			uploadFrom(reader);
 		}
 
+
+		/**
+		 * Read data from the given buffered reader and send it to the server
+		 * @param reader reader to read from
+		 * @throws IOException
+		 */
 		public void uploadFrom(Reader reader) throws IOException {
 			OutputStream s = getStream();
 			OutputStreamWriter writer = new OutputStreamWriter(s, StandardCharsets.UTF_8);
@@ -3357,6 +3412,9 @@ public class MonetConnection
 		}
 	}
 
+	/**
+	 * Handle passed to {@link MonetDownloadHandler} to allow communication with the server
+	 */
 	public static class Download {
 		private final MapiSocket server;
 		private MapiSocket.DownloadStream stream = null;
@@ -3368,6 +3426,21 @@ public class MonetConnection
 			this.server = server;
 		}
 
+		/**
+		 * Send an error message to the server
+		 *
+		 * The server will generally let the currently executing statement fail
+		 * with this error message. The connection will remain usable.
+		 *
+		 * This method can only be sent if no data has been received from the server
+		 * yet. After data has been received, you can still throw an
+		 * {@link IOException} but this will terminate the connection.
+		 * 
+		 * Note: as of MonetDB version Jul2021 the server always terminates the connection
+		 * when this error is used.  This will probably change in the future.
+		 * @param errorMessage
+		 * @throws IOException
+		 */
 		public void sendError(String errorMessage) throws IOException {
 			if (error != null) {
 				throw new IOException("another error has already been sent: " + error);
@@ -3375,6 +3448,13 @@ public class MonetConnection
 			error = errorMessage;
 		}
 
+		/**
+		 * Get an {@link InputStream} to read data from.
+		 * 
+		 * Textual data is UTF-8 encoded.
+		 * @return
+		 * @throws IOException
+		 */
 		public InputStream getStream() throws IOException {
 			if (error != null) {
 				throw new IOException("cannot receive data after error has been sent");
@@ -3386,6 +3466,11 @@ public class MonetConnection
 			return stream;
 		}
 
+		/**
+		 * Write the data from the server to the given {@link OutputStream}.
+		 * @param stream
+		 * @throws IOException
+		 */
 		public void downloadTo(OutputStream stream) throws IOException {
 			InputStream s = getStream();
 			byte[] buffer = new byte[65536];
@@ -3397,10 +3482,20 @@ public class MonetConnection
 			}
 		}
 
+		/**
+		 * Returns true if data has been received or an error has been sent.
+		 * @return
+		 */
+
 		public boolean hasBeenUsed() {
 			return error != null || stream != null;
 		}
 
+		/**
+		 * Get the error that was sent, if any
+		 * @return
+		 */
+
 		public String getError() {
 			return error;
 		}
@@ -3413,6 +3508,5 @@ public class MonetConnection
 			}
 			closed = true;
 		}
-
 	}
 }
--- a/src/main/java/org/monetdb/jdbc/MonetDownloadHandler.java
+++ b/src/main/java/org/monetdb/jdbc/MonetDownloadHandler.java
@@ -2,6 +2,21 @@ package org.monetdb.jdbc;
 
 import java.io.IOException;
 
+/**
+ * Callback for receiving files with COPY ON CLIENT
+ *
+ * To be registered with {@link MonetConnection#setDownloadHandler(MonetDownloadHandler)}
+ */
 public interface MonetDownloadHandler {
+	/**
+	 * Called if the server sends a request to write a file.
+	 * 
+	 * Use the given handle to send data or errors to the server.
+	 * 
+	 * @param handle Handle to communicate with the server
+	 * @param name Name of the file the server would like to write. Make sure to validate this before writing to
+	 *             the file system
+	 * @param textMode Whether this is text or binary data.
+	 */
 	void handleDownload(MonetConnection.Download handle, String name, boolean textMode) throws IOException;
-}
+}
\ No newline at end of file
--- a/src/main/java/org/monetdb/jdbc/MonetUploadHandler.java
+++ b/src/main/java/org/monetdb/jdbc/MonetUploadHandler.java
@@ -2,6 +2,22 @@ package org.monetdb.jdbc;
 
 import java.io.IOException;
 
+/**
+ * Callback for sending files for COPY ON CLIENT
+ *
+ * To be registered with {@link MonetConnection#setUploadHandler(MonetUploadHandler)}
+ */
+
 public interface MonetUploadHandler {
+	/**
+	 * Called if the server sends a request to write a file.
+	 *
+	 * Use the given handle to receive data or send errors to the server.
+	 *
+	 * @param handle Handle to communicate with the server
+	 * @param name Name of the file the server would like to read. Make sure to validate this before reading from
+	 *             the file system
+	 * @param textMode Whether this is text or binary data.
+	 */
 	void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, int offset) throws IOException;
-}
+}
\ No newline at end of file
--- a/src/main/java/org/monetdb/mcl/io/LineType.java
+++ b/src/main/java/org/monetdb/mcl/io/LineType.java
@@ -1,5 +1,8 @@
 package org.monetdb.mcl.io;
 
+/**
+ * Enumeration of the various message types used in the MAPI protocol.
+ */
 public enum LineType {
 	/** "there is currently no line", or the the type is unknown is represented by UNKNOWN */
 	UNKNOWN(null),
@@ -41,6 +44,9 @@ public enum LineType {
 		return this.bytes;
 	}
 
+	/**
+	 * Look at a mapi message and decide the LineType
+	 */
 	public static final LineType classify(String line) {
 		if (line == null) {
 			return UNKNOWN;
@@ -54,6 +60,9 @@ public enum LineType {
 		}
 	}
 
+	/**
+	 * Look at a mapi message and decide the LineType
+	 */
 	public static final LineType classify(byte[] line) {
 		if (line == null) {
 			return UNKNOWN;
--- a/src/main/java/org/monetdb/mcl/net/MapiSocket.java
+++ b/src/main/java/org/monetdb/mcl/net/MapiSocket.java
@@ -720,6 +720,9 @@ public class MapiSocket {	/* cannot (yet
 		return handshakeOptions;
 	}
 
+	/**
+	 * For internal use
+	 */
 	public boolean setInsertFakePrompts(boolean b) {
 		return fromMonet.setInsertFakePrompts(b);
 	}
@@ -1081,6 +1084,9 @@ public class MapiSocket {	/* cannot (yet
 			return n;
 		}
 
+		/**
+		 * For internal use
+		 */
 		Raw getRaw() {
 			return new Raw();
 		}
@@ -1164,14 +1170,31 @@ public class MapiSocket {	/* cannot (yet
 		}
 	}
 
+	/**
+	 * Return an UploadStream for use with for example COPY FROM filename ON CLIENT.
+	 *
+	 * Building block for {@link org.monetdb.jdbc.MonetUploadHandler}.
+	 * @param chunkSize chunk size for the upload stream
+	 */
 	public UploadStream uploadStream(int chunkSize) {
 		return new UploadStream(chunkSize);
 	}
 
+	/**
+	 * Return an UploadStream for use with for example COPY FROM filename ON CLIENT.
+	 *
+	 * Building block for {@link org.monetdb.jdbc.MonetUploadHandler}.
+	 */
 	public UploadStream uploadStream() {
 		return new UploadStream();
 	}
 
+	/**
+	 * Return a DownloadStream for use with for example COPY INTO filename ON CLIENT
+	 *
+	 * Building block for {@link org.monetdb.jdbc.MonetDownloadHandler}.
+	 * @return
+	 */
 	public DownloadStream downloadStream() {
 		return new DownloadStream(fromMonet.getRaw(), toMonet);
 	}
@@ -1190,6 +1213,14 @@ public class MapiSocket {	/* cannot (yet
 		super.finalize();
 	}
 
+	/**
+	 * Stream of data sent to the server
+	 * 
+ 	 * Building block for {@link org.monetdb.jdbc.MonetUploadHandler}.
+	 *
+	 * An UploadStream has a chunk size. Every chunk size bytes, the server gets
+	 * the opportunity to abort the upload.
+	 */
 	public class UploadStream extends FilterOutputStream {
 		public final static int DEFAULT_CHUNK_SIZE = 1024 * 1024;
 		private final int chunkSize;
@@ -1198,6 +1229,7 @@ public class MapiSocket {	/* cannot (yet
 		private int chunkLeft;
 		private byte[] promptBuffer;
 
+		/** Create an UploadStream with the given chunk size */
 		UploadStream(int chunkSize) {
 			super(toMonet);
 			if (chunkSize <= 0) {
@@ -1210,6 +1242,7 @@ public class MapiSocket {	/* cannot (yet
 			chunkLeft = this.chunkSize;
 		}
 
+		/** Create an UploadStream with the default chunk size */
 		UploadStream() {
 			this(DEFAULT_CHUNK_SIZE);
 		}
@@ -1323,6 +1356,11 @@ public class MapiSocket {	/* cannot (yet
 		}
 	}
 
+	/**
+	 * Stream of data received from the server
+	 * 
+ 	 * Building block for {@link org.monetdb.jdbc.MonetDownloadHandler}.
+	 */
 	public static class DownloadStream extends InputStream {
 
 		private final BlockInputStream.Raw rawIn;
@@ -1390,6 +1428,4 @@ public class MapiSocket {	/* cannot (yet
 				return off - origOff;
 		}
 	}
-
-
 }
--- a/src/main/java/org/monetdb/util/FileTransferHandler.java
+++ b/src/main/java/org/monetdb/util/FileTransferHandler.java
@@ -14,15 +14,34 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 
+/**
+ * Sample implement of ON CLIENT handling
+ *
+ * Can be registered with {@link MonetConnection#setUploadHandler(MonetUploadHandler)}
+ * and {@link MonetConnection#setDownloadHandler(MonetDownloadHandler)}.
+ * Implements uploads and downloads by reading and writing files on the file system.
+ */
 public class FileTransferHandler implements MonetUploadHandler, MonetDownloadHandler {
 	private final Path root;
 	private final boolean utf8Encoded;
 
+	/**
+	 * Create a new FileTransferHandler which serves the given directory.
+	 *
+	 * @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) {
 		root = dir.toAbsolutePath().normalize();
 		this.utf8Encoded = utf8Encoded;
 	}
 
+	/**
+	 * Create a new FileTransferHandler which serves the given directory.
+	 *
+	 * @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) {
 		this(FileSystems.getDefault().getPath(dir), utf8Encoded);
 	}
@@ -57,6 +76,5 @@ public class FileTransferHandler impleme
 			return;
 		}
 		OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE_NEW);
-
 	}
-}
+}
\ No newline at end of file
--- a/tests/build.xml
+++ b/tests/build.xml
@@ -106,6 +106,7 @@ Copyright 1997 - July 2008 CWI, August 2
 
   <target name="test_class" depends="compile,jdbc">
     <echo message="Testing class ${test.class}" />
+    <!-- fork="true" allows the test program to call System.exit() -->
     <java classname="${test.class}" failonerror="true" fork="true">
       <classpath>
         <pathelement path="${builddir}" />