Bug 573797: Refactor code to use Charset instead of passing around Strings

This simplifies error handling as once you have a Charset you don't
have to worry about whether or not an UnsupportedEncodingException can
be thrown anymore. In addition it is a little easier on type safety.

Change-Id: I4292878a7c621f9d05fdb98f5c26a0ae8bfec062
diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.control/META-INF/MANIFEST.MF
index 2a6a497..c2f710d 100644
--- a/terminal/plugins/org.eclipse.tm.terminal.control/META-INF/MANIFEST.MF
+++ b/terminal/plugins/org.eclipse.tm.terminal.control/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.tm.terminal.control; singleton:=true
-Bundle-Version: 5.2.100.qualifier
+Bundle-Version: 5.3.0.qualifier
 Bundle-Activator: org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalViewControl.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalViewControl.java
index 8ecccd5..d08a36c 100644
--- a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalViewControl.java
+++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalViewControl.java
@@ -17,6 +17,7 @@
 package org.eclipse.tm.internal.terminal.control;
 
 import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
 
 import org.eclipse.swt.dnd.Clipboard;
 import org.eclipse.swt.graphics.Font;
@@ -38,18 +39,38 @@
 	 *
 	 * @see ITerminalControl#setEncoding(String)
 	 * @since org.eclipse.tm.terminal 2.0
+	 * @deprecated Use {@link #setCharset(Charset)} and do the error handling in the UI code.
 	 */
+	@Deprecated
 	void setEncoding(String encoding) throws UnsupportedEncodingException;
 
 	/**
+	 * Set the charset that the Terminal uses to decode byte streams into
+	 * characters.
+	 *
+	 * @see ITerminalControl#setCharset(Charset)
+	 * @since 5.3
+	 */
+	void setCharset(Charset charset);
+
+	/**
 	 * Get the Terminal's current encoding.
 	 *
 	 * @return the current Encoding of the Terminal.
 	 * @see ITerminalControl#getEncoding()
 	 * @since org.eclipse.tm.terminal 2.0
+	 * @deprecated Use {@link #getCharset()} and call {@link Charset#name()} on the result
 	 */
+	@Deprecated
 	String getEncoding();
 
+	/**
+	 * @return the non-<code>null</code> current Charset of the Terminal.
+	 * @see ITerminalControl#getCharset()
+	 * @since 5.3
+	 */
+	Charset getCharset();
+
 	boolean isEmpty();
 
 	/**
diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java
index dda0980..759c16c 100644
--- a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java
+++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java
@@ -156,8 +156,7 @@
 	private boolean connectOnEnterIfClosed = true;
 
 	PipedInputStream fInputStream;
-	private static final String defaultEncoding = Charset.defaultCharset().name();
-	private String fEncoding = defaultEncoding;
+	private Charset fCharset = Charset.defaultCharset();
 	private InputStreamReader fInputStreamReader;
 
 	private ICommandInputField fCommandInputField;
@@ -230,38 +229,43 @@
 		fTerminalModel.setMaxHeight(1000);
 		fInputStream = new PipedInputStream(8 * 1024);
 		fTerminalText = new VT100Emulator(fTerminalModel, this, null);
-		try {
-			// Use Default Encoding as start, until setEncoding() is called
-			setEncoding(null);
-		} catch (UnsupportedEncodingException e) {
-			// Should never happen
-			e.printStackTrace();
-			// Fall back to local Platform Default Encoding
-			fEncoding = defaultEncoding;
-			fInputStreamReader = new InputStreamReader(fInputStream);
-			fTerminalText.setInputStreamReader(fInputStreamReader);
-		}
-
+		// Use Default Charset as start, until setCharset() is called
+		setCharset(Charset.defaultCharset());
 		setupTerminal(wndParent);
 	}
 
 	@Override
+	@Deprecated
 	public void setEncoding(String encoding) throws UnsupportedEncodingException {
+		Charset charset;
 		if (encoding == null) {
-			// TODO better use a standard remote-to-local encoding?
-			encoding = "ISO-8859-1"; //$NON-NLS-1$
-			// TODO or better use the local default encoding?
-			// encoding = defaultEncoding;
+			charset = Charset.defaultCharset();
+		} else {
+			charset = Charset.forName(encoding);
 		}
-		fInputStreamReader = new InputStreamReader(fInputStream, encoding);
 		// remember encoding if above didn't throw an exception
-		fEncoding = encoding;
+		setCharset(charset);
+	}
+
+	@Override
+	public void setCharset(Charset charset) {
+		if (charset == null) {
+			charset = Charset.defaultCharset();
+		}
+		fInputStreamReader = new InputStreamReader(fInputStream, charset);
+		fCharset = charset;
 		fTerminalText.setInputStreamReader(fInputStreamReader);
 	}
 
 	@Override
+	@Deprecated
 	public String getEncoding() {
-		return fEncoding;
+		return fCharset.name();
+	}
+
+	@Override
+	public Charset getCharset() {
+		return fCharset;
 	}
 
 	@Override
@@ -547,7 +551,7 @@
 			// TODO: Find a way to force this to use the ISO Latin-1 encoding.
 			// TODO: handle Encoding Errors in a better way
 
-			getOutputStream().write(string.getBytes(fEncoding));
+			getOutputStream().write(string.getBytes(fCharset));
 			getOutputStream().flush();
 		} catch (SocketException socketException) {
 			displayTextInTerminal(socketException.getMessage());
@@ -591,7 +595,7 @@
 					//
 					// TODO: Make the ESCAPE-vs-highbit behavior user configurable.
 
-					byte[] bytesToSend = String.valueOf(chKey).getBytes(fEncoding);
+					byte[] bytesToSend = String.valueOf(chKey).getBytes(fCharset);
 					StringBuilder b = new StringBuilder("sending ESC"); //$NON-NLS-1$
 					for (int i = 0; i < bytesToSend.length; i++) {
 						if (i != 0)
@@ -602,7 +606,7 @@
 					os.write('\u001b');
 					os.write(bytesToSend);
 				} else {
-					byte[] bytesToSend = String.valueOf(chKey).getBytes(fEncoding);
+					byte[] bytesToSend = String.valueOf(chKey).getBytes(fCharset);
 					StringBuilder b = new StringBuilder("sending"); //$NON-NLS-1$
 					for (int i = 0; i < bytesToSend.length; i++) {
 						if (i != 0)
@@ -826,10 +830,7 @@
 
 	private void writeToTerminal(String text) {
 		try {
-			getRemoteToTerminalOutputStream().write(text.getBytes(fEncoding));
-		} catch (UnsupportedEncodingException e) {
-			// should never happen!
-			e.printStackTrace();
+			getRemoteToTerminalOutputStream().write(text.getBytes(fCharset));
 		} catch (IOException e) {
 			// should never happen!
 			e.printStackTrace();
diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ITerminalControl.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ITerminalControl.java
index 226f03c..267f7ac 100644
--- a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ITerminalControl.java
+++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ITerminalControl.java
@@ -18,6 +18,7 @@
 
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
 
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Shell;
@@ -83,10 +84,40 @@
 	 * LANG on UNIX systems.
 	 *
 	 * @since org.eclipse.tm.terminal 2.0
+	 * @deprecated Use {@link #setCharset(Charset)} and do the error handling in the UI code.
 	 */
+	@Deprecated
 	void setEncoding(String encoding) throws UnsupportedEncodingException;
 
 	/**
+	 * Set the charset that the Terminal uses to decode bytes from the
+	 * Terminal-to-remote-Stream into Unicode Characters used in Java; or, to
+	 * encode Characters typed by the user into bytes sent over the wire to the
+	 * remote.
+	 *
+	 * By default, the local Platform Default charset is used. Also note that
+	 * the encoding must not be applied in case the terminal stream is processed
+	 * by some data transfer protocol which requires binary data.
+	 *
+	 * Validity of the charset set here is not checked. Since some encodings do
+	 * not cover the entire range of Unicode characters, it can happen that a
+	 * particular Unicode String typed in by the user can not be encoded into a
+	 * byte Stream with the encoding specified. and UnsupportedEncodingException
+	 * will be thrown in this case at the time the String is about to be
+	 * processed.
+	 *
+	 * The concrete encoding to use can either be specified manually by a user,
+	 * by means of a dialog, or a connector can try to obtain it automatically
+	 * from the remote side e.g. by evaluating an environment variable such as
+	 * LANG on UNIX systems.
+	 *
+	 * @param charset Charset to use, or <code>null</code> for platform's default charset.
+	 *
+	 * @since 5.3
+	 */
+	void setCharset(Charset charset);
+
+	/**
 	 * Return the current encoding. That's interesting when the previous
 	 * setEncoding() call failed and the fallback default encoding should be
 	 * queried, such that e.g. a combobox with encodings to choose can be
@@ -94,10 +125,20 @@
 	 *
 	 * @return the current Encoding of the Terminal.
 	 * @since org.eclipse.tm.terminal 2.0
+	 * @deprecated Use {@link #getCharset()} and call {@link Charset#name()} on the result
 	 */
+	@Deprecated
 	String getEncoding();
 
 	/**
+	 * Return the current charset.
+	 *
+	 * @return the non-<code>null</code> current charset of the Terminal
+	 * @since 5.3
+	 */
+	Charset getCharset();
+
+	/**
 	 * Show a text in the terminal. If puts newlines at the beginning and the
 	 * end.
 	 *
diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorFactoryTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorFactoryTest.java
index 5a6df0f..9cea03f 100644
--- a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorFactoryTest.java
+++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorFactoryTest.java
@@ -17,6 +17,7 @@
 package org.eclipse.tm.internal.terminal.connector;
 
 import java.io.OutputStream;
+import java.nio.charset.Charset;
 
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.swt.widgets.Composite;
@@ -54,11 +55,20 @@
 		}
 
 		@Override
+		public void setCharset(Charset charset) {
+		}
+
+		@Override
 		public String getEncoding() {
 			return "ISO-8859-1"; //$NON-NLS-1$
 		}
 
 		@Override
+		public Charset getCharset() {
+			return Charset.defaultCharset();
+		}
+
+		@Override
 		public void displayTextInTerminal(String text) {
 		}
 
diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorTest.java
index b9816aa..98f7519 100644
--- a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorTest.java
+++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorTest.java
@@ -17,6 +17,7 @@
 package org.eclipse.tm.internal.terminal.connector;
 
 import java.io.OutputStream;
+import java.nio.charset.Charset;
 
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Shell;
@@ -54,11 +55,20 @@
 		}
 
 		@Override
+		public void setCharset(Charset charset) {
+		}
+
+		@Override
 		public String getEncoding() {
 			return "ISO-8859-1"; //$NON-NLS-1$
 		}
 
 		@Override
+		public Charset getCharset() {
+			return Charset.defaultCharset();
+		}
+
+		@Override
 		public void displayTextInTerminal(String text) {
 		}
 
diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/SelectEncodingAction.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/SelectEncodingAction.java
index 622c887..8b7177a 100644
--- a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/SelectEncodingAction.java
+++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/SelectEncodingAction.java
@@ -11,8 +11,6 @@
  *******************************************************************************/
 package org.eclipse.tm.terminal.view.ui.actions;
 
-import java.io.UnsupportedEncodingException;
-
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.resource.ImageDescriptor;
@@ -53,14 +51,10 @@
 			return;
 
 		EncodingSelectionDialog dialog = new EncodingSelectionDialog(null);
-		dialog.setEncoding(target.getEncoding());
+		dialog.setCharset(target.getCharset());
 		if (dialog.open() == Window.OK) {
-			try {
-				target.setEncoding(dialog.getEncoding());
-				tabFolderManager.updateStatusLine();
-			} catch (UnsupportedEncodingException e) {
-				e.printStackTrace();
-			}
+			target.setCharset(dialog.getCharset());
+			tabFolderManager.updateStatusLine();
 		}
 	}
 
diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/dialogs/EncodingSelectionDialog.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/dialogs/EncodingSelectionDialog.java
index efb9395..96b9c90 100644
--- a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/dialogs/EncodingSelectionDialog.java
+++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/dialogs/EncodingSelectionDialog.java
@@ -11,6 +11,9 @@
  *******************************************************************************/
 package org.eclipse.tm.terminal.view.ui.internal.dialogs;
 
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.jface.dialogs.TrayDialog;
 import org.eclipse.swt.SWT;
@@ -33,7 +36,7 @@
 	private String contextHelpId = null;
 
 	// The selected encoding or null
-	/* default */ String encoding = null;
+	private String encoding;
 
 	// Reference to the encodings panel
 	private EncodingPanel encodingPanel = null;
@@ -194,16 +197,25 @@
 	}
 
 	/**
-	 * Set the encoding to default to on creating the dialog.
+	 * Set the charset to default to on creating the dialog.
 	 */
-	public final void setEncoding(String encoding) {
-		this.encoding = encoding;
+
+	public void setCharset(Charset charset) {
+		this.encoding = charset == null ? null : charset.name();
 	}
 
 	/**
-	 * Returns the selected encoding or <code>null</code>.
+	 * Returns the selected charset or <code>null</code>.
 	 */
-	public final String getEncoding() {
-		return encoding;
+	public final Charset getCharset() {
+		if (encoding == null) {
+			return null;
+		}
+		try {
+			return Charset.forName(encoding);
+		} catch (UnsupportedCharsetException e) {
+			return null;
+		}
 	}
+
 }
diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderManager.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderManager.java
index 661e1af..955b782 100644
--- a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderManager.java
+++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderManager.java
@@ -11,7 +11,8 @@
  *******************************************************************************/
 package org.eclipse.tm.terminal.view.ui.tabs;
 
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -279,8 +280,12 @@
 			new TerminalControlSelectionListener(terminal);
 			// Configure the terminal encoding
 			try {
-				terminal.setEncoding(encoding);
-			} catch (UnsupportedEncodingException e) {
+				Charset charset = null;
+				if (encoding != null) {
+					charset = Charset.forName(encoding);
+				}
+				terminal.setCharset(charset);
+			} catch (UnsupportedCharsetException e) {
 				/* ignored on purpose */
 			}
 			// Associated the terminal with the tab item