Explanation
It's not about wait. I think this is what happens:
You use <<, so stdin of ssh is redirected to some descriptor through which the entire here document flows.
This other answer explains how ssh is able to capture Ctrl+C when -t is used. This is what matters:
On the client side, ssh will try to set the tty used by stdin to "raw" mode […] Setting raw mode means that characters that would normally send signals (such as Ctrl+C) are instead just inserted into the input stream.
In your case it's not the same stdin your local shell uses. tty used by your local shell is left intact, it is never set to "raw" mode.
So when you hit Ctrl+C it acts locally and terminates ssh. At this moment the remote side gets SIGHUP. Your trap works and kills java. I think there's a pitfall here: a trap executes some code in response to a given signal but it doesn't prevent the signal from having its normal effect. Therefore it looks to me your java would be killed even without a trap because it's a job of the shell that gets terminated in response to SIGHUP.
The shell that gets terminated stops reading and interpreting its stdin. That's why everything that follows wait is discarded.
Solution
commands() { cat <<-'COMMANDS'
cleanup() {
# cleanup code here
echo "Done. Logging out"
sleep 2
logout
}
echo "Preparing execution"
java -jar execute.jar &
executePID=$!
echo "Ready."
echo "CTRL+C to clean and close"
trap "kill $executePID; cleanup" INT HUP
wait $executePID
cleanup
COMMANDS
}
stty raw -echo; cat <(commands) - | ssh -t $USER@remote.far; stty -raw echo
The last line is the actual command. First we prepare tty so Ctrl+C cannot act locally. Then we concatenate commands and standard input, we pass it to the remote shell. I cannot do this with here document directly, the command function is a workaround (it would be easier to use a regular file but you said you cannot use more than one). After ssh and cat exit we set the tty to its normal state.
Having pseudo-terminal is essential so make sure ssh -t works (use -tt if needed).
The remote shell must read (buffer) all the commands from commands, only then it can get Ctrl+C when you press it. I guess this means you cannot have too much code after wait. Additionally whatever you want to do after SIGINT must be run from inside the trap. These are the reasons I used a single cleanup function that does it all.
The code is not foolproof. Hit Ctrl+C too early or multiple times and you'll find yourself in the remote shell or with somewhat "broken" local tty. In this latter case use the command reset to reset your tty.
You must press a key (e.g. Enter) after you see "Connection to … closed." The reason is cat won't notice the pipe is broken (due to ssh being no more) until it tries to write something to it.
Alternative
If for any reason the above solution doesn't work for you, use this simpler alternative. The here document is exactly as before. In this case we don't mess with tty, Ctrl+C terminates local ssh as it does with your original code. The difference (with respect to your code) is the trap does the cleaning. I think it would be enough to trap SIGHUP only.
ssh -t $USER@remote.far <<-'COMMANDS'
cleanup() {
# cleanup code here
echo "Done. Logging out"
sleep 2
logout
}
echo "Preparing execution"
java -jar execute.jar &
executePID=$!
echo "Ready."
echo "CTRL+C to clean and close"
trap "kill $executePID; cleanup" INT HUP
wait $executePID
cleanup
COMMANDS
Note: when the trap is triggered cleanup echoes a message but you won't see it because your local ssh is already disconnected. You will see the message only if java exits without the trap. Still your cleanup code (# cleanup code here) should be executed.