Index: applications/editors/josm/plugins/geochat/src/geochat/ChatMessage.java
===================================================================
--- applications/editors/josm/plugins/geochat/src/geochat/ChatMessage.java	(revision 35161)
+++ applications/editors/josm/plugins/geochat/src/geochat/ChatMessage.java	(revision 35162)
@@ -11,5 +11,5 @@
  * @author zverik
  */
-public class ChatMessage implements Comparable<ChatMessage> {
+public final class ChatMessage implements Comparable<ChatMessage> {
     private LatLon pos;
     private Date time;
@@ -46,4 +46,5 @@
     /**
      * Is only set when the message is not incoming, that is, author is the current user.
+     * @return recipient
      */
     public String getRecipient() {
Index: applications/editors/josm/plugins/geochat/src/geochat/ChatPaneManager.java
===================================================================
--- applications/editors/josm/plugins/geochat/src/geochat/ChatPaneManager.java	(revision 35161)
+++ applications/editors/josm/plugins/geochat/src/geochat/ChatPaneManager.java	(revision 35162)
@@ -80,5 +80,5 @@
         int idx = tabs.indexOfComponent(entry.component);
         if (idx >= 0)
-            ((ChatTabTitleComponent) tabs.getTabComponentAt(idx)).updateAlarm();
+            GuiHelper.runInEDT(() -> ((ChatTabTitleComponent) tabs.getTabComponentAt(idx)).updateAlarm());
     }
 
@@ -171,4 +171,5 @@
      * Returns key in chatPanes hash map for the currently active
      * chat pane, or null in case of an error.
+     * @return key in chatPanes hash map for the currently active chat pane
      */
     public String getActiveChatPane() {
Index: applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnection.java
===================================================================
--- applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnection.java	(revision 35161)
+++ applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnection.java	(revision 35162)
@@ -87,4 +87,5 @@
      * Test that userId is still active, if not, tries to login with given user name.
      * Does not autologin, if userName is null, obviously.
+     * @param userName user name
      */
     public void autoLogin(final String userName) {
@@ -107,4 +108,5 @@
      * Waits until {@link #getPosition()} is not null, then calls {@link #autoLogin(java.lang.String)}.
      * If two seconds have passed, stops the waiting. Doesn't wait if userName is empty.
+     * @param userName user name
      */
     public void autoLoginWithDelay(final String userName) {
@@ -203,4 +205,5 @@
      * Unregister the current user and do not call listeners.
      * Makes synchronous request to the server.
+     * @throws IOException There was a problem connecting to the server or parsing JSON.
      */
     public void bruteLogout() throws IOException {
@@ -260,4 +263,5 @@
     /**
      * Returns current coordinates or null if there is no map, or zoom is too low.
+     * @return current coordinates or null
      */
     private static LatLon getPosition() {
@@ -360,5 +364,5 @@
             JsonObject json;
             try {
-                json = JsonQueryUtil.query(query);
+                json = JsonQueryUtil.query(query, true);
             } catch (IOException ex) {
                 json = null; // ?
Index: applications/editors/josm/plugins/geochat/src/geochat/JsonQueryUtil.java
===================================================================
--- applications/editors/josm/plugins/geochat/src/geochat/JsonQueryUtil.java	(revision 35161)
+++ applications/editors/josm/plugins/geochat/src/geochat/JsonQueryUtil.java	(revision 35162)
@@ -5,6 +5,4 @@
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
 import java.net.URL;
 
@@ -15,4 +13,6 @@
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.tools.HttpClient;
+import org.openstreetmap.josm.tools.HttpClient.Response;
 import org.openstreetmap.josm.tools.Logging;
 
@@ -26,29 +26,35 @@
     /**
      * Query the server synchronously.
-     * @param query Query string, starting with action. Example: <tt>get&lat=1.0&lon=-2.0&uid=12345</tt>
+     * @param query Query string, starting with action. Example: <tt>get&amp;lat=1.0&amp;lon=-2.0&amp;uid=12345</tt>
      * @return Parsed JsonObject if the query was successful, <tt>null</tt> otherwise.
      * @throws IOException There was a problem connecting to the server or parsing JSON.
      */
     public static JsonObject query(String query) throws IOException {
+        return query(query, false);
+    }
+
+    /**
+     * Query the server synchronously.
+     * @param query Query string, starting with action. Example: <tt>get&amp;lat=1.0&amp;lon=-2.0&amp;uid=12345</tt>
+     * @param logAtDebug {@code true} to set http client connection log at DEBUG level instead of default INFO level
+     * @return Parsed JsonObject if the query was successful, <tt>null</tt> otherwise.
+     * @throws IOException There was a problem connecting to the server or parsing JSON.
+     */
+    public static JsonObject query(String query, boolean logAtDebug) throws IOException {
+        String serverURL = Config.getPref().get("geochat.server", "https://zverik.dev.openstreetmap.org/osmochat.php?action=");
+        URL url = new URL(serverURL + query);
+        Response connection = HttpClient.create(url).setLogAtDebug(logAtDebug).connect();
+        if (connection.getResponseCode() != 200) {
+            throw new IOException("HTTP Response code " + connection.getResponseCode() + " (" + connection.getResponseMessage() + ")");
+        }
+        InputStream inp = connection.getContent();
+        if (inp == null)
+            throw new IOException("Empty response");
         try {
-            String serverURL = Config.getPref().get("geochat.server", "https://zverik.dev.openstreetmap.org/osmochat.php?action=");
-            URL url = new URL(serverURL + query);
-            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-            connection.connect();
-            if (connection.getResponseCode() != 200) {
-                throw new IOException("HTTP Response code " + connection.getResponseCode() + " (" + connection.getResponseMessage() + ")");
-            }
-            InputStream inp = connection.getInputStream();
-            if (inp == null)
-                throw new IOException("Empty response");
-            try {
-                return Json.createReader(inp).readObject();
-            } catch (JsonException e) {
-                throw new IOException("Failed to parse JSON: " + e.getMessage());
-            } finally {
-                connection.disconnect();
-            }
-        } catch (MalformedURLException ex) {
-            throw new IOException("Malformed URL: " + ex.getMessage());
+            return Json.createReader(inp).readObject();
+        } catch (JsonException e) {
+            throw new IOException("Failed to parse JSON: " + e.getMessage(), e);
+        } finally {
+            connection.disconnect();
         }
     }
