From 89580369bcb8118fcfe2d30d5c9ac13cb0a92bc3 Mon Sep 17 00:00:00 2001 From: wizard Date: Sat, 8 Nov 2025 23:50:04 +0100 Subject: [PATCH 1/8] with properties --- .gitignore | 6 ++ src/server/config/ServerProperties.java | 27 ++++++ src/server/config/ServerPropertiesValue.java | 23 +++++ src/server/config/ServerXmlConfigValue.java | 23 +++++ ...ServerConfig.java => XmlServerConfig.java} | 4 +- src/server/core/Server.java | 83 +++++++++++-------- src/server/utils/FileUtils.java | 46 ++++++++-- 7 files changed, 170 insertions(+), 42 deletions(-) create mode 100644 src/server/config/ServerProperties.java create mode 100644 src/server/config/ServerPropertiesValue.java create mode 100644 src/server/config/ServerXmlConfigValue.java rename src/server/config/{ServerConfig.java => XmlServerConfig.java} (97%) diff --git a/.gitignore b/.gitignore index e8240f8..1d31be5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ /bin/ /.idea/ +/target/ +.DS_Store +/build/ +/out/ +/.vscode/ +/production/ \ No newline at end of file diff --git a/src/server/config/ServerProperties.java b/src/server/config/ServerProperties.java new file mode 100644 index 0000000..b2fd1ce --- /dev/null +++ b/src/server/config/ServerProperties.java @@ -0,0 +1,27 @@ +package server.config; +import java.util.*; + +public class ServerProperties extends Properties { + private static final long serialVersionUID = 1L; + +// private static ResourceBundle bundle = ResourceBundle.getBundle("config"); +// +// public static ResourceBundle getBundle(String baseName) { +// return bundle; +// } + + @Override + public synchronized Object put(Object key, Object value) { + return super.put(key, value); + } + + @Override + public synchronized Object get(Object key) { + return super.get(key); + } + + public static int getConfigValueAsInt(String val) { + return ServerPropertiesValue.getConfigValueAsInt(val); + } + +} \ No newline at end of file diff --git a/src/server/config/ServerPropertiesValue.java b/src/server/config/ServerPropertiesValue.java new file mode 100644 index 0000000..9f01cee --- /dev/null +++ b/src/server/config/ServerPropertiesValue.java @@ -0,0 +1,23 @@ +package server.config; + +import server.core.Server; + +public class ServerPropertiesValue { + private static String getConfigValue(String val) { + ServerProperties cfg = Server.getServerProperties(); + if (cfg == null) return ""; + String v = (String)cfg.get(val); + return v == null ? "" : v; + } + + @SuppressWarnings("unused") + public static int getConfigValueAsInt(String val) { + String v = getConfigValue(val); + try { + return Integer.parseInt(v); + } catch (NumberFormatException e) { +// Server.LOGGER.warning("NumberFormatException: " + e.getMessage()); + return -1; + } + } +} diff --git a/src/server/config/ServerXmlConfigValue.java b/src/server/config/ServerXmlConfigValue.java new file mode 100644 index 0000000..fed4a9d --- /dev/null +++ b/src/server/config/ServerXmlConfigValue.java @@ -0,0 +1,23 @@ +package server.config; + +import server.core.Server; + +public class ServerXmlConfigValue { + private static String getConfigValue(String val) { + XmlServerConfig cfg = Server.getXmlConfig(); + if (cfg == null) return ""; + String v = cfg.get(val); + return v == null ? "" : v; + } + + @SuppressWarnings("unused") + public static int getConfigValueAsInt(String val) { + String v = getConfigValue(val); + try { + return Integer.parseInt(v); + } catch (NumberFormatException e) { +// Server.LOGGER.warning("NumberFormatException: " + e.getMessage()); + return -1; + } + } +} diff --git a/src/server/config/ServerConfig.java b/src/server/config/XmlServerConfig.java similarity index 97% rename from src/server/config/ServerConfig.java rename to src/server/config/XmlServerConfig.java index b9e74ed..1ffad47 100644 --- a/src/server/config/ServerConfig.java +++ b/src/server/config/XmlServerConfig.java @@ -22,10 +22,10 @@ import org.xml.sax.SAXParseException; -public class ServerConfig { +public class XmlServerConfig { private final Map parameters = new HashMap(); - public ServerConfig(String file) { + public XmlServerConfig(String file) { read(file); } diff --git a/src/server/core/Server.java b/src/server/core/Server.java index 3a6af0b..7082b8b 100644 --- a/src/server/core/Server.java +++ b/src/server/core/Server.java @@ -1,8 +1,11 @@ package server.core; -import server.config.ServerConfig; +import server.config.*; import server.utils.FileUtils; +import java.util.logging.Logger; +// import java.util.logging.Level; // unused + import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; @@ -10,7 +13,6 @@ import java.util.List; import java.util.ArrayList; import java.util.Collections; -import java.util.Properties; import server.module.*; @@ -18,20 +20,25 @@ * @author andrzej.salamon@gmail.com */ public final class Server extends Thread { + private static final Logger LOGGER = Logger.getLogger(Server.class.getName()); + + private static final String ERR_PORT_PREFIX = "failed listening on port: "; private static final String FILE_CONFIG_SERVER_XML = "server.xml"; private static final String FILE_CONFIG_SERVER_PROPS = "server.properties"; - private static final String FILE_CONFIG_SERVER_YML = "server.yml"; + // private static final String FILE_CONFIG_SERVER_YML = "server.yml"; // wont implement till now + + private static final String DIR_CONFIG = "config"; - public static final String DIR_CONFIG = "config"; +// removed unused commented code - private Properties properties; + private static ServerProperties serverProperties; private ServerSocket serverSocket = null; private ServerSocket serverWebSocket = null; private ServerSocket serverWeb = null; public static final String IP = getIp(); - private static ServerConfig config; + private static XmlServerConfig config; // thread-safe list wrapper private final List connections = Collections.synchronizedList(new ArrayList()); @@ -44,26 +51,33 @@ public final class Server extends Thread { public Server() { - Server.setConfig(new ServerConfig(DIR_CONFIG + FileUtils.FILE_SEPARATOR + FILE_CONFIG_SERVER_XML)); + // Server.setConfig(new XmlServerConfig(DIR_CONFIG + FileUtils.FILE_SEPARATOR + FILE_CONFIG_SERVER_XML)); + try { + setServerProperties(FileUtils.loadServerProperties(DIR_CONFIG + FileUtils.FILE_SEPARATOR + FILE_CONFIG_SERVER_PROPS)); + } catch (IOException e) { + e.printStackTrace(); + startFailed = true; + System.exit(1); + } try { setServerSocket(new ServerSocket(getSocketPort())); } catch (IOException e) { - System.err.println("failed listening on port: " + getSocketPort() + " -> " + e.getMessage()); + LOGGER.severe(ERR_PORT_PREFIX + getSocketPort() + " -> " + e.getMessage()); startFailed = true; } try { setServerWebSocket(new ServerSocket(getWebsocketPort())); } catch (IOException e) { - System.err.println("failed listening on port: " + getWebsocketPort() + " -> " + e.getMessage()); + LOGGER.severe(ERR_PORT_PREFIX + getWebsocketPort() + " -> " + e.getMessage()); startFailed = true; } try { setServerWeb(new ServerSocket(getWebPort())); } catch (IOException e) { - System.err.println("failed listening on port: " + getWebPort() + " -> " + e.getMessage()); + LOGGER.severe(ERR_PORT_PREFIX + getWebPort() + " -> " + e.getMessage()); startFailed = true; } @@ -77,31 +91,15 @@ public Server() { } private static int getWebPort() { - return getConfigValueAsInt("webPort"); + return ServerPropertiesValue.getConfigValueAsInt("webPort"); } private static int getWebsocketPort() { - return getConfigValueAsInt("websocketPort"); + return ServerPropertiesValue.getConfigValueAsInt("websocketPort"); } private static int getSocketPort() { - return getConfigValueAsInt("socketPort"); - } - - private static String getConfigValue(String val) { - ServerConfig cfg = getConfig(); - if (cfg == null) return ""; - String v = cfg.get(val); - return v == null ? "" : v; - } - - private static int getConfigValueAsInt(String val) { - String v = getConfigValue(val); - try { - return Integer.parseInt(v); - } catch (NumberFormatException e) { - return 0; - } + return ServerPropertiesValue.getConfigValueAsInt("socketPort"); } private void setServerWeb(ServerSocket serverWebPort) { @@ -134,9 +132,9 @@ private void startModules() { conn.start(); } catch (IllegalThreadStateException e) { // already started or cannot start; log and continue - System.err.println("module start failed: " + e.getMessage()); + LOGGER.severe("module start failed: " + e.getMessage()); } catch (Exception e) { - System.err.println("unexpected module start error: " + e.getMessage()); + LOGGER.severe("unexpected module start error: " + e.getMessage()); } } } @@ -149,23 +147,33 @@ private void stopModules() { try { conn.stop(); } catch (Exception e) { - System.err.println("module stop failed: " + e.getMessage()); + LOGGER.severe("module stop failed: " + e.getMessage()); } } } } - public static ServerConfig getConfig() { + public static XmlServerConfig getXmlConfig() { return config; } - public static void setConfig(ServerConfig config) { + public static void setXmlConfig(XmlServerConfig config) { Server.config = config; } + public static ServerProperties getServerProperties() { + return serverProperties; + } + + public static void setServerProperties(ServerProperties config) { + Server.serverProperties = config; + } + @Override + @SuppressWarnings("unused") public void run() { - System.out.println("Andrew (Web)Socket(s) Server v. 1.1"); + LOGGER.info("Andrew (Web)Socket(s) Server v. 1.1"); + LOGGER.info("Started at IP: " + IP); startModules(); running = true; @@ -173,6 +181,7 @@ public void run() { try { Thread.sleep(1000); // sleep server for a while } catch (InterruptedException e) { + LOGGER.warning("InterruptedException: " + e.getMessage()); // restore interrupted status and exit loop Thread.currentThread().interrupt(); running = false; @@ -188,11 +197,13 @@ public void run() { stopServer(); } + @SuppressWarnings("unused") private static String getIp() { try { InetAddress addr = InetAddress.getLocalHost(); return addr.getHostAddress(); } catch (UnknownHostException e) { + LOGGER.warning("UnknownHostException: " + e.getMessage()); return ""; } } @@ -224,11 +235,13 @@ public void stopServer() { closeQuietly(serverWeb); } + @SuppressWarnings("unused") private void closeQuietly(ServerSocket s) { if (s == null) return; try { s.close(); } catch (IOException e) { + LOGGER.warning("IOException closing socket: " + e.getMessage()); // swallow - best effort close } } diff --git a/src/server/utils/FileUtils.java b/src/server/utils/FileUtils.java index b045741..3c2f185 100644 --- a/src/server/utils/FileUtils.java +++ b/src/server/utils/FileUtils.java @@ -1,11 +1,10 @@ package server.utils; -import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.NoSuchFileException; -import java.text.ParseException; -import java.text.SimpleDateFormat; - -import java.util.Date; +import server.config.ServerProperties; /** * @author andrzej.salamon@gmail.com @@ -13,9 +12,46 @@ */ public class FileUtils { + /** + * Singleton instance of {@link FileUtils}. The instance is created eagerly and is + * therefore thread‑safe without requiring additional synchronization. + */ + private static final FileUtils INSTANCE = new FileUtils(); + + /** + * Private constructor to prevent external instantiation. The class provides a + * singleton instance via {@link #getInstance()}. + */ + private FileUtils() { + // Prevent instantiation + } + + /** + * Returns the singleton instance of {@link FileUtils}. + * + * @return the singleton {@code FileUtils} instance + */ + public static FileUtils getInstance() { + return INSTANCE; + } + public static final String FILE_SEPARATOR = getFileseparator(); public static String getFileseparator() { return System.getProperty("file.separator"); } + + public static ServerProperties loadServerProperties(String fileName) throws IOException { + // First try to load from the file system using the supplied path. + ServerProperties properties = new ServerProperties(); + ClassLoader loader = FileUtils.class.getClassLoader(); + + InputStream stream = loader.getResourceAsStream(fileName); + if (stream == null) { + // If the resource is not found, mimic the previous behavior by throwing NoSuchFileException + throw new NoSuchFileException(fileName); + } + properties.load(stream); + return properties; + } } From 5812639f0393c87f2341ee78b8352a25e2199a90 Mon Sep 17 00:00:00 2001 From: wizard Date: Thu, 11 Dec 2025 06:58:51 +0100 Subject: [PATCH 2/8] refactoring, added properties, config --- .gitignore | 3 +- config/server.properties | 8 +- src/server/config/ServerPropertiesValue.java | 10 +- src/server/core/ConnectionAbstract.java | 4 + src/server/core/Server.java | 107 +++++++++++------- .../connection/WebConnectionAbstract.java | 2 +- .../WebSocketConnectionAbstract.java | 2 +- src/server/module/SocketModule.java | 50 ++++---- src/server/module/WebModule.java | 14 ++- src/server/module/WebSocketModule.java | 6 +- src/server/utils/FileUtils.java | 3 +- 11 files changed, 130 insertions(+), 79 deletions(-) diff --git a/.gitignore b/.gitignore index 1d31be5..a8ce7d4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ /build/ /out/ /.vscode/ -/production/ \ No newline at end of file +/production/ +/openJDK-25/ \ No newline at end of file diff --git a/config/server.properties b/config/server.properties index e1669ec..9badca2 100644 --- a/config/server.properties +++ b/config/server.properties @@ -1,3 +1,9 @@ socketPort=6050 websocketPort=6051 -webPort=8080 \ No newline at end of file +webPort=8080 +enabledProtocols=socket,websocket,web +socketEnabled=true +websocketEnabled=true +webEnabled=true +sslEnabled=false +maxConnections=100 \ No newline at end of file diff --git a/src/server/config/ServerPropertiesValue.java b/src/server/config/ServerPropertiesValue.java index 9f01cee..78aa6ae 100644 --- a/src/server/config/ServerPropertiesValue.java +++ b/src/server/config/ServerPropertiesValue.java @@ -2,7 +2,7 @@ import server.core.Server; -public class ServerPropertiesValue { +public final class ServerPropertiesValue { private static String getConfigValue(String val) { ServerProperties cfg = Server.getServerProperties(); if (cfg == null) return ""; @@ -20,4 +20,12 @@ public static int getConfigValueAsInt(String val) { return -1; } } + public static String getConfigValueAsString(String val) { + return getConfigValue(val); + } + + public static boolean getConfigValueAsBoolean(String val) { + String v = getConfigValue(val); + return v.equalsIgnoreCase("true") || v.equalsIgnoreCase("yes") || v.equals("1"); + } } diff --git a/src/server/core/ConnectionAbstract.java b/src/server/core/ConnectionAbstract.java index 9f621e5..2169ecf 100644 --- a/src/server/core/ConnectionAbstract.java +++ b/src/server/core/ConnectionAbstract.java @@ -101,4 +101,8 @@ public void processStream() { // throw new RuntimeException(e); } } + + protected void flushOutputStream() throws IOException { + outputStream.flush(); + } } diff --git a/src/server/core/Server.java b/src/server/core/Server.java index 7082b8b..687a7d1 100644 --- a/src/server/core/Server.java +++ b/src/server/core/Server.java @@ -13,6 +13,7 @@ import java.util.List; import java.util.ArrayList; import java.util.Collections; +import java.util.logging.Level; import server.module.*; @@ -20,17 +21,22 @@ * @author andrzej.salamon@gmail.com */ public final class Server extends Thread { + private static final Logger LOGGER = Logger.getLogger(Server.class.getName()); private static final String ERR_PORT_PREFIX = "failed listening on port: "; - private static final String FILE_CONFIG_SERVER_XML = "server.xml"; + // private static final String FILE_CONFIG_SERVER_XML = "server.xml"; private static final String FILE_CONFIG_SERVER_PROPS = "server.properties"; - // private static final String FILE_CONFIG_SERVER_YML = "server.yml"; // wont implement till now + // private static final String FILE_CONFIG_SERVER_YML = "server.yml"; // wont + // implement till now private static final String DIR_CONFIG = "config"; + private static final String CFG_ENABLED_PROTOCOLS = "enabledProtocols"; + private static final String CFG_WEB_ENABLED = "webEnabled"; + private static final String CFG_WEBSOCKET_ENABLED = "websocketEnabled"; + private static final String CFG_SOCKET_ENABLED = "socketEnabled"; -// removed unused commented code - + // removed unused commented code private static ServerProperties serverProperties; private ServerSocket serverSocket = null; @@ -44,45 +50,60 @@ public final class Server extends Thread { private final List connections = Collections.synchronizedList(new ArrayList()); // flags used across threads - private volatile boolean running; + private volatile boolean running = false; private volatile boolean stop = false; private volatile boolean exitOnFail = true; private volatile boolean startFailed = false; public Server() { - // Server.setConfig(new XmlServerConfig(DIR_CONFIG + FileUtils.FILE_SEPARATOR + FILE_CONFIG_SERVER_XML)); + // Server.setConfig(new XmlServerConfig(DIR_CONFIG + FileUtils.FILE_SEPARATOR + + // FILE_CONFIG_SERVER_XML)); try { - setServerProperties(FileUtils.loadServerProperties(DIR_CONFIG + FileUtils.FILE_SEPARATOR + FILE_CONFIG_SERVER_PROPS)); + setServerProperties( + FileUtils.loadServerProperties(DIR_CONFIG + FileUtils.FILE_SEPARATOR + FILE_CONFIG_SERVER_PROPS)); } catch (IOException e) { - e.printStackTrace(); + LOGGER.severe(e.getMessage()); startFailed = true; - System.exit(1); + System.exit(-1); } - try { - setServerSocket(new ServerSocket(getSocketPort())); - } catch (IOException e) { - LOGGER.severe(ERR_PORT_PREFIX + getSocketPort() + " -> " + e.getMessage()); + if (getSocketPort() < 1 || getWebsocketPort() < 1 || getWebPort() < 1) { + LOGGER.severe("Invalid port configuration. Ports must be greater than 0."); startFailed = true; + System.exit(-1); } - try { - setServerWebSocket(new ServerSocket(getWebsocketPort())); - } catch (IOException e) { - LOGGER.severe(ERR_PORT_PREFIX + getWebsocketPort() + " -> " + e.getMessage()); - startFailed = true; - } + if (ServerPropertiesValue.getConfigValueAsBoolean(CFG_SOCKET_ENABLED) + || ServerPropertiesValue.getConfigValueAsString(CFG_ENABLED_PROTOCOLS).contains("socket")) + try { + setServerSocket(new ServerSocket(getSocketPort())); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, ERR_PORT_PREFIX + "{0} -> {1}", + new Object[] { getSocketPort(), e.getMessage() }); + startFailed = true; + } - try { - setServerWeb(new ServerSocket(getWebPort())); - } catch (IOException e) { - LOGGER.severe(ERR_PORT_PREFIX + getWebPort() + " -> " + e.getMessage()); - startFailed = true; - } + if (ServerPropertiesValue.getConfigValueAsBoolean(CFG_WEBSOCKET_ENABLED) + || ServerPropertiesValue.getConfigValueAsString(CFG_ENABLED_PROTOCOLS).contains("websocket")) + try { + setServerWebSocket(new ServerSocket(getWebsocketPort())); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, ERR_PORT_PREFIX + "{0} -> {1}", + new Object[] { getWebsocketPort(), e.getMessage() }); + startFailed = true; + } + + if (ServerPropertiesValue.getConfigValueAsBoolean(CFG_WEB_ENABLED)) + try { + setServerWeb(new ServerSocket(getWebPort())); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, ERR_PORT_PREFIX + "{0} -> {1}", new Object[] { getWebPort(), e.getMessage() }); + startFailed = true; + } if (startFailed && exitOnFail) { - System.exit(1); + System.exit(-1); } addDefaultModules(); @@ -118,7 +139,9 @@ private ServerSocket getServerWeb() { } public void addModule(SocketConnection socketConnection) { - if (socketConnection == null) return; + if (socketConnection == null) { + return; + } if (!connections.contains(socketConnection)) { connections.add(socketConnection); } @@ -126,15 +149,17 @@ public void addModule(SocketConnection socketConnection) { private void startModules() { synchronized (connections) { - if (connections.isEmpty()) return; + if (connections.isEmpty()) { + return; + } for (SocketConnection conn : connections) { try { conn.start(); } catch (IllegalThreadStateException e) { // already started or cannot start; log and continue - LOGGER.severe("module start failed: " + e.getMessage()); + LOGGER.log(Level.SEVERE, "module start failed: {0}", e.getMessage()); } catch (Exception e) { - LOGGER.severe("unexpected module start error: " + e.getMessage()); + LOGGER.log(Level.SEVERE, "unexpected module start error: {0}", e.getMessage()); } } } @@ -142,12 +167,14 @@ private void startModules() { private void stopModules() { synchronized (connections) { - if (connections.isEmpty()) return; + if (connections.isEmpty()) { + return; + } for (SocketConnection conn : connections) { try { conn.stop(); } catch (Exception e) { - LOGGER.severe("module stop failed: " + e.getMessage()); + LOGGER.log(Level.SEVERE, "module stop failed: {0}", e.getMessage()); } } } @@ -173,7 +200,7 @@ public static void setServerProperties(ServerProperties config) { @SuppressWarnings("unused") public void run() { LOGGER.info("Andrew (Web)Socket(s) Server v. 1.1"); - LOGGER.info("Started at IP: " + IP); + LOGGER.log(Level.INFO, "Started at IP: {0}", IP); startModules(); running = true; @@ -181,7 +208,7 @@ public void run() { try { Thread.sleep(1000); // sleep server for a while } catch (InterruptedException e) { - LOGGER.warning("InterruptedException: " + e.getMessage()); + LOGGER.log(Level.WARNING, "InterruptedException: {0}", e.getMessage()); // restore interrupted status and exit loop Thread.currentThread().interrupt(); running = false; @@ -203,7 +230,7 @@ private static String getIp() { InetAddress addr = InetAddress.getLocalHost(); return addr.getHostAddress(); } catch (UnknownHostException e) { - LOGGER.warning("UnknownHostException: " + e.getMessage()); + LOGGER.log(Level.WARNING, "UnknownHostException: {0}", e.getMessage()); return ""; } } @@ -237,11 +264,13 @@ public void stopServer() { @SuppressWarnings("unused") private void closeQuietly(ServerSocket s) { - if (s == null) return; + if (s == null) { + return; + } try { s.close(); } catch (IOException e) { - LOGGER.warning("IOException closing socket: " + e.getMessage()); + LOGGER.log(Level.WARNING, "IOException closing socket: {0}", e.getMessage()); // swallow - best effort close } } @@ -253,10 +282,6 @@ public void requestStop() { public static void main(String[] args) { Server server = new Server(); - // optionally handle start failure - if (server.startFailed && server.exitOnFail) { - System.exit(1); - } } } diff --git a/src/server/core/connection/WebConnectionAbstract.java b/src/server/core/connection/WebConnectionAbstract.java index 0d1279a..37050ab 100644 --- a/src/server/core/connection/WebConnectionAbstract.java +++ b/src/server/core/connection/WebConnectionAbstract.java @@ -7,7 +7,7 @@ public abstract class WebConnectionAbstract extends ConnectionAbstract implements SocketConnection { - public WebConnectionAbstract(ServerSocket serverSocket) { + protected WebConnectionAbstract(ServerSocket serverSocket) { super(serverSocket); } diff --git a/src/server/core/connection/WebSocketConnectionAbstract.java b/src/server/core/connection/WebSocketConnectionAbstract.java index 23cda66..e0968c4 100644 --- a/src/server/core/connection/WebSocketConnectionAbstract.java +++ b/src/server/core/connection/WebSocketConnectionAbstract.java @@ -143,7 +143,7 @@ public void broadcast(String data) throws IOException { } outputStream.write(responseByte); - outputStream.flush(); + flushOutputStream(); } diff --git a/src/server/module/SocketModule.java b/src/server/module/SocketModule.java index c6fe039..b35bd68 100644 --- a/src/server/module/SocketModule.java +++ b/src/server/module/SocketModule.java @@ -9,8 +9,8 @@ /** * @author andrzej.salamon@gmail.com */ -public final class SocketModule extends SocketConnectionAbstract { - public final static String MODULE_NAME = "socket"; +public class SocketModule extends SocketConnectionAbstract { + public static final String MODULE_NAME = "socketModule"; public SocketModule(ServerSocket serverSocket) { super(serverSocket); @@ -27,35 +27,35 @@ public void run() { processStream(); receive(); broadcast(); - outputStream.flush(); -// out.close(); -// in.close(); -// getClient().close(); -// try { -//// out.close(); -//// in.close(); -// client.close(); -// } catch (IOException e) { -// // e.printStackTrace(); -// } + flushOutputStream(); + // out.close(); + // in.close(); + // getClient().close(); + // try { + //// out.close(); + //// in.close(); + // client.close(); + // } catch (IOException e) { + // // e.printStackTrace(); + // } } catch (Exception e) { } } } -// @Override -// public void start() { -// -// } -// -// @Override -// public void stop() { -// -// } + // @Override + // public void start() { + // + // } + // + // @Override + // public void stop() { + // + // } @Override public void receive() throws IOException { -// request = (SerializedSocketObject)in.readObject(); + // request = (SerializedSocketObject)in.readObject(); } @Override @@ -64,7 +64,7 @@ public void broadcast() throws IOException { @Override public void broadcast(String data) throws IOException { -// response = process(request); -// out.writeObject(response); + // response = process(request); + // out.writeObject(response); } } diff --git a/src/server/module/WebModule.java b/src/server/module/WebModule.java index ebc6f0c..a745b4e 100644 --- a/src/server/module/WebModule.java +++ b/src/server/module/WebModule.java @@ -1,6 +1,5 @@ package server.module; -import server.core.connection.SocketConnectionAbstract; import server.core.connection.WebConnectionAbstract; import java.io.IOException; @@ -10,7 +9,7 @@ /** * @author andrzej.salamon@gmail.com */ -public final class WebModule extends WebConnectionAbstract { +public class WebModule extends WebConnectionAbstract { public static final String MODULE_NAME = "webModuleSocket"; private PrintWriter printWriter; @@ -30,7 +29,7 @@ public void run() { processStream(); receive(); broadcast(); - outputStream.flush(); + flushOutputStream(); // out.close(); // in.close(); // getClient().close(); @@ -54,7 +53,16 @@ public void receive() throws IOException { @Override public void broadcast() throws IOException { + printWriter = new PrintWriter(outputStream, true); + printWriter.println("HTTP/1.1 200 OK"); + printWriter.println("Content-Type: text/html"); + printWriter.println(); + printWriter.println("

Hello, World!

"); + flushPrintWriter(); + } + private void flushPrintWriter() { + printWriter.flush(); } @Override diff --git a/src/server/module/WebSocketModule.java b/src/server/module/WebSocketModule.java index 91196bf..4dcec30 100644 --- a/src/server/module/WebSocketModule.java +++ b/src/server/module/WebSocketModule.java @@ -9,8 +9,8 @@ /** * @author andrzej.salamon@gmail.com */ -public final class WebSocketModule extends WebSocketConnectionAbstract { //double inheritance, not ellegant, ref,mv - public static final String MODULE_NAME = "websocket"; +public class WebSocketModule extends WebSocketConnectionAbstract { //double inheritance, not ellegant, ref,mv + public static final String MODULE_NAME = "websocketModule"; public WebSocketModule(ServerSocket serverSocket) { @@ -53,7 +53,7 @@ public void run() { e.printStackTrace(); } try { - outputStream.flush(); + flushOutputStream(); } catch (IOException e) { System.err.println("cant flush"); e.printStackTrace(); diff --git a/src/server/utils/FileUtils.java b/src/server/utils/FileUtils.java index 3c2f185..de828e2 100644 --- a/src/server/utils/FileUtils.java +++ b/src/server/utils/FileUtils.java @@ -2,7 +2,6 @@ import java.io.IOException; import java.io.InputStream; -import java.nio.file.NoSuchFileException; import server.config.ServerProperties; @@ -49,7 +48,7 @@ public static ServerProperties loadServerProperties(String fileName) throws IOEx InputStream stream = loader.getResourceAsStream(fileName); if (stream == null) { // If the resource is not found, mimic the previous behavior by throwing NoSuchFileException - throw new NoSuchFileException(fileName); + throw new IOException(fileName); } properties.load(stream); return properties; From 0011cc164ca7969fb447ff450ba3796864476a72 Mon Sep 17 00:00:00 2001 From: wizard Date: Sat, 13 Dec 2025 02:27:41 +0100 Subject: [PATCH 3/8] refactoring --- config/server.properties | 5 +- src/server/config/ConfigConstant.java | 14 +++ src/server/config/ServerXmlConfigValue.java | 1 + src/server/config/XmlServerConfig.java | 2 +- src/server/core/Connection.java | 1 + src/server/core/ConnectionAbstract.java | 12 +- src/server/core/HttpMethod.java | 11 ++ src/server/core/Listener.java | 8 ++ src/server/core/Responsive.java | 6 - src/server/core/Server.java | 114 +++++++++++------- .../WebSocketConnectionAbstract.java | 31 ++--- .../core/listener/HttpMethodListener.java | 26 ++++ src/server/module/SocketModule.java | 2 + src/server/module/WebModule.java | 2 + src/server/module/WebSocketModule.java | 14 ++- 15 files changed, 180 insertions(+), 69 deletions(-) create mode 100644 src/server/config/ConfigConstant.java create mode 100644 src/server/core/HttpMethod.java create mode 100644 src/server/core/Listener.java delete mode 100644 src/server/core/Responsive.java create mode 100644 src/server/core/listener/HttpMethodListener.java diff --git a/config/server.properties b/config/server.properties index 9badca2..1f4c0c1 100644 --- a/config/server.properties +++ b/config/server.properties @@ -1,9 +1,10 @@ socketPort=6050 websocketPort=6051 webPort=8080 -enabledProtocols=socket,websocket,web socketEnabled=true websocketEnabled=true webEnabled=true sslEnabled=false -maxConnections=100 \ No newline at end of file +maxConnections=100 +#not implemented yet, something like front controller pattern +serverAsDispatcher=false \ No newline at end of file diff --git a/src/server/config/ConfigConstant.java b/src/server/config/ConfigConstant.java new file mode 100644 index 0000000..79c85bd --- /dev/null +++ b/src/server/config/ConfigConstant.java @@ -0,0 +1,14 @@ +package server.config; + +public class ConfigConstant { + public static final String ENABLED_PROTOCOLS = "enabledProtocols"; + public static final String WEB_ENABLED = "webEnabled"; + public static final String WEBSOCKET_ENABLED = "websocketEnabled"; + public static final String SOCKET_ENABLED = "socketEnabled"; + public static final String WEB_PORT = "webPort"; + public static final String WEBSOCKET_PORT = "websocketPort"; + public static final String SOCKET_PORT = "socketPort"; + public static final String VALUE_WEB = "web"; + public static final String VALUE_WEBSOCKET = "websocket"; + public static final String VALUE_SOCKET = "socket"; +} diff --git a/src/server/config/ServerXmlConfigValue.java b/src/server/config/ServerXmlConfigValue.java index fed4a9d..724330f 100644 --- a/src/server/config/ServerXmlConfigValue.java +++ b/src/server/config/ServerXmlConfigValue.java @@ -2,6 +2,7 @@ import server.core.Server; +@Deprecated public class ServerXmlConfigValue { private static String getConfigValue(String val) { XmlServerConfig cfg = Server.getXmlConfig(); diff --git a/src/server/config/XmlServerConfig.java b/src/server/config/XmlServerConfig.java index 1ffad47..db9af6d 100644 --- a/src/server/config/XmlServerConfig.java +++ b/src/server/config/XmlServerConfig.java @@ -21,7 +21,7 @@ import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; - +@Deprecated public class XmlServerConfig { private final Map parameters = new HashMap(); diff --git a/src/server/core/Connection.java b/src/server/core/Connection.java index 360a32d..9a07e70 100644 --- a/src/server/core/Connection.java +++ b/src/server/core/Connection.java @@ -11,4 +11,5 @@ public interface Connection { void receive() throws IOException; void broadcast() throws IOException; void broadcast(String data) throws IOException; + int getPort(); } diff --git a/src/server/core/ConnectionAbstract.java b/src/server/core/ConnectionAbstract.java index 2169ecf..535a874 100644 --- a/src/server/core/ConnectionAbstract.java +++ b/src/server/core/ConnectionAbstract.java @@ -10,7 +10,7 @@ * @todo add factory */ public abstract class ConnectionAbstract implements Runnable, Connection { - protected static int counter = 0; + protected static int counter; protected final Thread thread; // protected ObjectOutputStream out; // protected ObjectInputStream in; @@ -26,14 +26,22 @@ public abstract class ConnectionAbstract implements Runnable, Connection { protected boolean stop = false; protected java.net.Socket client; protected ServerSocket serverSocket; + protected int port; protected ConnectionAbstract(ServerSocket serverSocket) { + setCounter(0); this.serverSocket = serverSocket; - this.instanceNo = counter++; + this.port = serverSocket.getLocalPort(); + this.instanceNo = getCounter(); + incrementCounter(); this.thread = new Thread(this, MODULE_NAME + instanceNo); } + public int getPort() { + return port; + } + public static int getCounter() { return counter; } diff --git a/src/server/core/HttpMethod.java b/src/server/core/HttpMethod.java new file mode 100644 index 0000000..59dcc5a --- /dev/null +++ b/src/server/core/HttpMethod.java @@ -0,0 +1,11 @@ +package server.core; + +public enum HttpMethod { + GET, + POST, + PUT, + DELETE, + HEAD, + OPTIONS, + PATCH +} diff --git a/src/server/core/Listener.java b/src/server/core/Listener.java new file mode 100644 index 0000000..4a3bd27 --- /dev/null +++ b/src/server/core/Listener.java @@ -0,0 +1,8 @@ +package server.core; + +public interface Listener { + void onReceive(T message); + void onBroadcast(T message); + T onBroadcast(); + T onReceive(); +} diff --git a/src/server/core/Responsive.java b/src/server/core/Responsive.java deleted file mode 100644 index 0135bc8..0000000 --- a/src/server/core/Responsive.java +++ /dev/null @@ -1,6 +0,0 @@ -package server.core; - -public interface Responsive { - String onBroadcast(); - String onReceive(); -} diff --git a/src/server/core/Server.java b/src/server/core/Server.java index 687a7d1..a862375 100644 --- a/src/server/core/Server.java +++ b/src/server/core/Server.java @@ -31,12 +31,14 @@ public final class Server extends Thread { // implement till now private static final String DIR_CONFIG = "config"; - private static final String CFG_ENABLED_PROTOCOLS = "enabledProtocols"; - private static final String CFG_WEB_ENABLED = "webEnabled"; - private static final String CFG_WEBSOCKET_ENABLED = "websocketEnabled"; - private static final String CFG_SOCKET_ENABLED = "socketEnabled"; + public static final String FORMAT_PARAM_LOGGER = "{0} -> {1}"; + + public enum MODULES { + SOCKET, + WEBSOCKET, + WEB + } - // removed unused commented code private static ServerProperties serverProperties; private ServerSocket serverSocket = null; @@ -44,6 +46,7 @@ public final class Server extends Thread { private ServerSocket serverWeb = null; public static final String IP = getIp(); + @Deprecated private static XmlServerConfig config; // thread-safe list wrapper @@ -52,13 +55,20 @@ public final class Server extends Thread { // flags used across threads private volatile boolean running = false; private volatile boolean stop = false; + + public boolean isExitOnFail() { + return exitOnFail; + } + + public void setExitOnFail(boolean exitOnFail) { + this.exitOnFail = exitOnFail; + } + private volatile boolean exitOnFail = true; private volatile boolean startFailed = false; public Server() { - - // Server.setConfig(new XmlServerConfig(DIR_CONFIG + FileUtils.FILE_SEPARATOR + - // FILE_CONFIG_SERVER_XML)); + //we are not using nio because we want to have it synchronous try { setServerProperties( FileUtils.loadServerProperties(DIR_CONFIG + FileUtils.FILE_SEPARATOR + FILE_CONFIG_SERVER_PROPS)); @@ -74,66 +84,87 @@ public Server() { System.exit(-1); } - if (ServerPropertiesValue.getConfigValueAsBoolean(CFG_SOCKET_ENABLED) - || ServerPropertiesValue.getConfigValueAsString(CFG_ENABLED_PROTOCOLS).contains("socket")) - try { - setServerSocket(new ServerSocket(getSocketPort())); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, ERR_PORT_PREFIX + "{0} -> {1}", - new Object[] { getSocketPort(), e.getMessage() }); - startFailed = true; - } + configureModule(ConfigConstant.SOCKET_ENABLED, getSocketPort(), MODULES.SOCKET); + configureModule(ConfigConstant.WEBSOCKET_ENABLED, getWebsocketPort(), MODULES.WEBSOCKET); + configureModule(ConfigConstant.WEB_ENABLED, getWebPort(), MODULES.WEB); - if (ServerPropertiesValue.getConfigValueAsBoolean(CFG_WEBSOCKET_ENABLED) - || ServerPropertiesValue.getConfigValueAsString(CFG_ENABLED_PROTOCOLS).contains("websocket")) - try { - setServerWebSocket(new ServerSocket(getWebsocketPort())); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, ERR_PORT_PREFIX + "{0} -> {1}", - new Object[] { getWebsocketPort(), e.getMessage() }); - startFailed = true; - } + if (startFailed && exitOnFail) { + System.exit(-1); + } - if (ServerPropertiesValue.getConfigValueAsBoolean(CFG_WEB_ENABLED)) + this.start(); + } + + private void configureModule(String socketEnabled, int socketPort, MODULES module) { + if (isEnabled(socketEnabled)) try { - setServerWeb(new ServerSocket(getWebPort())); + setupModule(module, socketPort); } catch (IOException e) { - LOGGER.log(Level.SEVERE, ERR_PORT_PREFIX + "{0} -> {1}", new Object[] { getWebPort(), e.getMessage() }); + LOGGER.log(Level.SEVERE, ERR_PORT_PREFIX + FORMAT_PARAM_LOGGER, + new Object[]{socketPort, e.getMessage()}); startFailed = true; } + } - if (startFailed && exitOnFail) { - System.exit(-1); + private static boolean isEnabled(String socketEnabled) { + return ServerPropertiesValue.getConfigValueAsBoolean(socketEnabled); + } + + private void setupModule(MODULES module, int socketPort) throws IOException { + switch (module) { + case SOCKET: + setServerSocket(createSocket(socketPort)); + addSocketModule(); + break; + case WEBSOCKET: + setServerWebSocket(createSocket(socketPort)); + addWebsocketModule(); + break; + case WEB: + setServerWeb(createSocket(socketPort)); + addWebModule(); + break; + default: + LOGGER.severe("Unknown module type"); + break; } + } - addDefaultModules(); + private void addModule() { + } - this.start(); + private static ServerSocket createSocket(int port) throws IOException { + return new ServerSocket(port); } private static int getWebPort() { - return ServerPropertiesValue.getConfigValueAsInt("webPort"); + return ServerPropertiesValue.getConfigValueAsInt(ConfigConstant.WEB_PORT); } private static int getWebsocketPort() { - return ServerPropertiesValue.getConfigValueAsInt("websocketPort"); + return ServerPropertiesValue.getConfigValueAsInt(ConfigConstant.WEBSOCKET_PORT); } private static int getSocketPort() { - return ServerPropertiesValue.getConfigValueAsInt("socketPort"); + return ServerPropertiesValue.getConfigValueAsInt(ConfigConstant.SOCKET_PORT); } private void setServerWeb(ServerSocket serverWebPort) { this.serverWeb = serverWebPort; } - private void addDefaultModules() { - // add modules; connections list is thread-safe - addModule(new WebSocketModule(getServerWebSocket())); // sharing sockets intentionally - addModule(new SocketModule(getServerSocket())); + private void addWebModule() { addModule(new WebModule(getServerWeb())); } + private void addSocketModule() { + addModule(new SocketModule(getServerSocket())); + } + + private void addWebsocketModule() { + addModule(new WebSocketModule(getServerWebSocket())); + } + private ServerSocket getServerWeb() { return serverWeb; } @@ -154,6 +185,7 @@ private void startModules() { } for (SocketConnection conn : connections) { try { + LOGGER.log(Level.INFO, "Starting module: {0} at port {1}", new Object[] { conn.getClass().getSimpleName(), conn.getPort() } ); conn.start(); } catch (IllegalThreadStateException e) { // already started or cannot start; log and continue @@ -224,7 +256,6 @@ public void run() { stopServer(); } - @SuppressWarnings("unused") private static String getIp() { try { InetAddress addr = InetAddress.getLocalHost(); @@ -262,7 +293,6 @@ public void stopServer() { closeQuietly(serverWeb); } - @SuppressWarnings("unused") private void closeQuietly(ServerSocket s) { if (s == null) { return; diff --git a/src/server/core/connection/WebSocketConnectionAbstract.java b/src/server/core/connection/WebSocketConnectionAbstract.java index e0968c4..2d0095c 100644 --- a/src/server/core/connection/WebSocketConnectionAbstract.java +++ b/src/server/core/connection/WebSocketConnectionAbstract.java @@ -2,6 +2,7 @@ //import server.core; import server.core.ConnectionAbstract; +import server.core.HttpMethod; import server.core.WebSocketConnection; import javax.xml.bind.DatatypeConverter; @@ -16,7 +17,9 @@ public abstract class WebSocketConnectionAbstract extends ConnectionAbstract implements WebSocketConnection { - protected String secWebSocketKey; + protected static final String UUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + protected String secWebSocketKey; //@todo cache it with timeout + private byte[] responseBuffer; public WebSocketConnectionAbstract(ServerSocket serverSocket) { super(serverSocket); @@ -37,7 +40,7 @@ public void sendHandshake() throws NoSuchAlgorithmException, IOException { .printBase64Binary( MessageDigest .getInstance("SHA-1") - .digest((secWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + .digest((secWebSocketKey + UUID) .getBytes(StandardCharsets.UTF_8))) + "\r\n\r\n") .getBytes(StandardCharsets.UTF_8); @@ -56,23 +59,23 @@ private Matcher setSecWebSocketKey() { } public boolean isGet() { - Matcher get = Pattern.compile("^GET").matcher(request); + Matcher get = Pattern.compile("^"+ HttpMethod.GET).matcher(request); return get.find(); } public void receive() throws IOException { - byte[] buffer = new byte[server.core.WebSocketConnection.MAX_BUFFER]; + responseBuffer = new byte[WebSocketConnection.MAX_BUFFER]; int messageLength, mask, dataStart; - messageLength = inputStream.read(buffer); + messageLength = inputStream.read(responseBuffer); if (messageLength == -1) { return; } - requestByte = new byte[messageLength]; + responseByte = new byte[messageLength]; //b[0] is always text in my case so no need to check; - byte data = buffer[1]; //does it cause a problem ? + byte data = responseBuffer[1]; //does it cause a problem ? byte op = (byte) 127; byte length; @@ -86,17 +89,17 @@ public void receive() throws IOException { int j = 0, i=mask; for (; i < (mask + 4); i++) { //start at mask, stop at last + 4 - masks[j] = buffer[i]; //problem here + masks[j] = responseBuffer[i]; //problem here j++; } dataStart = mask + 4; for (i = dataStart, j = 0; i < messageLength; i++, j++) { - requestByte[j] = (byte) (buffer[i] ^ masks[j % 4]); + responseByte[j] = (byte) (responseBuffer[i] ^ masks[j % 4]); } - response = new String(requestByte); //why now string copy of byte ? + response = new String(responseByte); //why now string copy of byte ? } public void broadcast(String data) throws IOException { @@ -132,17 +135,17 @@ public void broadcast(String data) throws IOException { int responseLength = frameCount + rawData.length; int responseLimit = 0; - responseByte = new byte[responseLength]; + requestByte = new byte[responseLength]; for (; responseLimit < frameCount; responseLimit++) { - responseByte[responseLimit] = frame[responseLimit]; + requestByte[responseLimit] = frame[responseLimit]; } for (byte dataByte : rawData) { - responseByte[responseLimit++] = dataByte; + requestByte[responseLimit++] = dataByte; } - outputStream.write(responseByte); + outputStream.write(requestByte); flushOutputStream(); } diff --git a/src/server/core/listener/HttpMethodListener.java b/src/server/core/listener/HttpMethodListener.java new file mode 100644 index 0000000..12e0aff --- /dev/null +++ b/src/server/core/listener/HttpMethodListener.java @@ -0,0 +1,26 @@ +package server.core.listener; + +import server.core.Listener; + +public class HttpMethodListener implements Listener { + @Override + public void onReceive(Object message) { + + } + + @Override + public void onBroadcast(Object message) { + + } + + @Override + public Object onBroadcast() { + return null; + } + + @Override + public Object onReceive() { + return null; + } + +} diff --git a/src/server/module/SocketModule.java b/src/server/module/SocketModule.java index b35bd68..a69e76c 100644 --- a/src/server/module/SocketModule.java +++ b/src/server/module/SocketModule.java @@ -4,6 +4,7 @@ import java.net.ServerSocket; +import server.core.Server; import server.core.connection.SocketConnectionAbstract; /** @@ -11,6 +12,7 @@ */ public class SocketModule extends SocketConnectionAbstract { public static final String MODULE_NAME = "socketModule"; + public static final Server.MODULES MODULE_TYPE = Server.MODULES.SOCKET; public SocketModule(ServerSocket serverSocket) { super(serverSocket); diff --git a/src/server/module/WebModule.java b/src/server/module/WebModule.java index a745b4e..cc0ace5 100644 --- a/src/server/module/WebModule.java +++ b/src/server/module/WebModule.java @@ -1,5 +1,6 @@ package server.module; +import server.core.Server; import server.core.connection.WebConnectionAbstract; import java.io.IOException; @@ -11,6 +12,7 @@ */ public class WebModule extends WebConnectionAbstract { public static final String MODULE_NAME = "webModuleSocket"; + public static final Server.MODULES MODULE_TYPE = Server.MODULES.WEB; private PrintWriter printWriter; diff --git a/src/server/module/WebSocketModule.java b/src/server/module/WebSocketModule.java index 4dcec30..3e0f8fd 100644 --- a/src/server/module/WebSocketModule.java +++ b/src/server/module/WebSocketModule.java @@ -1,5 +1,6 @@ package server.module; +import server.core.Server; import server.core.connection.WebSocketConnectionAbstract; import java.io.IOException; @@ -11,6 +12,7 @@ */ public class WebSocketModule extends WebSocketConnectionAbstract { //double inheritance, not ellegant, ref,mv public static final String MODULE_NAME = "websocketModule"; + public static final Server.MODULES MODULE_TYPE = Server.MODULES.WEBSOCKET; public WebSocketModule(ServerSocket serverSocket) { @@ -59,13 +61,13 @@ public void run() { e.printStackTrace(); } try { - outputStream.close(); + closeOutputStream(); } catch (IOException e) { System.err.println("cant close output stream"); e.printStackTrace(); } try { - inputStream.close(); + closeInputStream(); } catch (IOException e) { System.err.println("cant inputSTream close"); e.printStackTrace(); @@ -85,4 +87,12 @@ public void run() { } } + private void closeInputStream() throws IOException { + inputStream.close(); + } + + private void closeOutputStream() throws IOException { + outputStream.close(); + } + } From a7bb66a49a3b294f888cc03dc2aab5da6f82e0e1 Mon Sep 17 00:00:00 2001 From: wizard Date: Thu, 18 Dec 2025 07:34:08 +0100 Subject: [PATCH 4/8] web module works. --- config/server.properties | 4 ++- src/server/config/ServerXmlConfigValue.java | 34 ++++++++++---------- src/server/core/ConnectionAbstract.java | 35 ++++++++++++++++++++- src/server/core/Server.java | 32 +++++-------------- src/server/core/SocketConnection.java | 1 + src/server/module/WebModule.java | 27 +++++++++++++--- src/server/module/WebSocketModule.java | 10 +----- 7 files changed, 87 insertions(+), 56 deletions(-) diff --git a/config/server.properties b/config/server.properties index 1f4c0c1..65d04e1 100644 --- a/config/server.properties +++ b/config/server.properties @@ -7,4 +7,6 @@ webEnabled=true sslEnabled=false maxConnections=100 #not implemented yet, something like front controller pattern -serverAsDispatcher=false \ No newline at end of file +serverAsDispatcher=false +#use this for dynamic port allocation +dynamicPortRange=6000-7000 \ No newline at end of file diff --git a/src/server/config/ServerXmlConfigValue.java b/src/server/config/ServerXmlConfigValue.java index 724330f..3da61ce 100644 --- a/src/server/config/ServerXmlConfigValue.java +++ b/src/server/config/ServerXmlConfigValue.java @@ -4,21 +4,21 @@ @Deprecated public class ServerXmlConfigValue { - private static String getConfigValue(String val) { - XmlServerConfig cfg = Server.getXmlConfig(); - if (cfg == null) return ""; - String v = cfg.get(val); - return v == null ? "" : v; - } - - @SuppressWarnings("unused") - public static int getConfigValueAsInt(String val) { - String v = getConfigValue(val); - try { - return Integer.parseInt(v); - } catch (NumberFormatException e) { -// Server.LOGGER.warning("NumberFormatException: " + e.getMessage()); - return -1; - } - } +// private static String getConfigValue(String val) { +// XmlServerConfig cfg = Server.getXmlConfig(); +// if (cfg == null) return ""; +// String v = cfg.get(val); +// return v == null ? "" : v; +// } +// +// @SuppressWarnings("unused") +// public static int getConfigValueAsInt(String val) { +// String v = getConfigValue(val); +// try { +// return Integer.parseInt(v); +// } catch (NumberFormatException e) { +//// Server.LOGGER.warning("NumberFormatException: " + e.getMessage()); +// return -1; +// } +// } } diff --git a/src/server/core/ConnectionAbstract.java b/src/server/core/ConnectionAbstract.java index 535a874..f56d058 100644 --- a/src/server/core/ConnectionAbstract.java +++ b/src/server/core/ConnectionAbstract.java @@ -85,7 +85,7 @@ public void stop() { instanceNo = -1; } - public void processStream(Socket client) { + public void processStreamBinary(Socket client) { try { setClient(client); outputStream = new ObjectOutputStream(getClient().getOutputStream()); @@ -110,7 +110,40 @@ public void processStream() { } } + public void processStream(Socket client) { + try { + setClient(client); + outputStream = getClient().getOutputStream(); + inputStream = getClient().getInputStream(); + } catch (IOException e) { + e.printStackTrace(); + } /*finally { + try { //try to close gracefully + client.close(); + } catch (IOException e) { + e.printStackTrace(); + } + }*/ + } + + public void processStreamBinary() { + try { + processStreamBinary(serverSocket.accept()); + } catch (IOException e) { + e.printStackTrace(); +// throw new RuntimeException(e); + } + } + protected void flushOutputStream() throws IOException { outputStream.flush(); } + + protected void closeInputStream() throws IOException { + inputStream.close(); + } + + protected void closeOutputStream() throws IOException { + outputStream.close(); + } } diff --git a/src/server/core/Server.java b/src/server/core/Server.java index a862375..d9ec6d5 100644 --- a/src/server/core/Server.java +++ b/src/server/core/Server.java @@ -23,31 +23,22 @@ public final class Server extends Thread { private static final Logger LOGGER = Logger.getLogger(Server.class.getName()); - private static final String ERR_PORT_PREFIX = "failed listening on port: "; - // private static final String FILE_CONFIG_SERVER_XML = "server.xml"; private static final String FILE_CONFIG_SERVER_PROPS = "server.properties"; - // private static final String FILE_CONFIG_SERVER_YML = "server.yml"; // wont - // implement till now - private static final String DIR_CONFIG = "config"; - public static final String FORMAT_PARAM_LOGGER = "{0} -> {1}"; + private static final String FORMAT_PARAM_LOGGER = "{0} -> {1}"; + public static final String IP = getIp(); public enum MODULES { SOCKET, WEBSOCKET, WEB - } + } private static ServerProperties serverProperties; - private ServerSocket serverSocket = null; private ServerSocket serverWebSocket = null; private ServerSocket serverWeb = null; - public static final String IP = getIp(); - - @Deprecated - private static XmlServerConfig config; // thread-safe list wrapper private final List connections = Collections.synchronizedList(new ArrayList()); @@ -68,12 +59,12 @@ public void setExitOnFail(boolean exitOnFail) { private volatile boolean startFailed = false; public Server() { - //we are not using nio because we want to have it synchronous + // we are not using nio because we want to have it synchronous try { setServerProperties( FileUtils.loadServerProperties(DIR_CONFIG + FileUtils.FILE_SEPARATOR + FILE_CONFIG_SERVER_PROPS)); } catch (IOException e) { - LOGGER.severe(e.getMessage()); + LOGGER.log(Level.SEVERE, "No configuration found: {0}", e.getMessage()); startFailed = true; System.exit(-1); } @@ -101,7 +92,7 @@ private void configureModule(String socketEnabled, int socketPort, MODULES modul setupModule(module, socketPort); } catch (IOException e) { LOGGER.log(Level.SEVERE, ERR_PORT_PREFIX + FORMAT_PARAM_LOGGER, - new Object[]{socketPort, e.getMessage()}); + new Object[] { socketPort, e.getMessage() }); startFailed = true; } } @@ -185,7 +176,8 @@ private void startModules() { } for (SocketConnection conn : connections) { try { - LOGGER.log(Level.INFO, "Starting module: {0} at port {1}", new Object[] { conn.getClass().getSimpleName(), conn.getPort() } ); + LOGGER.log(Level.INFO, "Starting module: {0} at port {1}", + new Object[] { conn.getClass().getSimpleName(), conn.getPort() }); conn.start(); } catch (IllegalThreadStateException e) { // already started or cannot start; log and continue @@ -212,14 +204,6 @@ private void stopModules() { } } - public static XmlServerConfig getXmlConfig() { - return config; - } - - public static void setXmlConfig(XmlServerConfig config) { - Server.config = config; - } - public static ServerProperties getServerProperties() { return serverProperties; } diff --git a/src/server/core/SocketConnection.java b/src/server/core/SocketConnection.java index 03b9bfe..ef4f5e9 100644 --- a/src/server/core/SocketConnection.java +++ b/src/server/core/SocketConnection.java @@ -9,5 +9,6 @@ public interface SocketConnection extends Connection { String getId(); void processStream(); + void processStreamBinary(); void processStream(Socket client); } diff --git a/src/server/module/WebModule.java b/src/server/module/WebModule.java index cc0ace5..ff6a843 100644 --- a/src/server/module/WebModule.java +++ b/src/server/module/WebModule.java @@ -3,7 +3,9 @@ import server.core.Server; import server.core.connection.WebConnectionAbstract; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; @@ -32,9 +34,8 @@ public void run() { receive(); broadcast(); flushOutputStream(); -// out.close(); -// in.close(); -// getClient().close(); + closeOutpInputStreams(); + getClient().close(); // try { //// out.close(); //// in.close(); @@ -48,9 +49,22 @@ public void run() { } } + private void closeOutpInputStreams() throws IOException { + outputStream.close(); + inputStream.close(); + } + @Override public void receive() throws IOException { + java.util.Scanner in = new java.util.Scanner(inputStream); + StringBuilder requestBuilder = new StringBuilder(); + String line; + while (in.hasNextLine() && !(line = in.nextLine()).isEmpty()) { + requestBuilder.append(line).append("\r\n"); + } + request = requestBuilder.toString(); + System.out.println("Received request:\n" + request); } @Override @@ -69,6 +83,11 @@ private void flushPrintWriter() { @Override public void broadcast(String data) throws IOException { - + printWriter = new PrintWriter(outputStream, true); + printWriter.println("HTTP/1.1 200 OK"); + printWriter.println("Content-Type: text/html"); + printWriter.println(); + printWriter.println(data); + flushPrintWriter(); } } diff --git a/src/server/module/WebSocketModule.java b/src/server/module/WebSocketModule.java index 3e0f8fd..65fa19e 100644 --- a/src/server/module/WebSocketModule.java +++ b/src/server/module/WebSocketModule.java @@ -26,7 +26,7 @@ public String getId() { public void run() { while (!stop) { - processStream(); + processStreamBinary(); request = getRequestAsString(); @@ -87,12 +87,4 @@ public void run() { } } - private void closeInputStream() throws IOException { - inputStream.close(); - } - - private void closeOutputStream() throws IOException { - outputStream.close(); - } - } From 97e3222e8c63729b5cfecdbff5dbc66980858945 Mon Sep 17 00:00:00 2001 From: wizard Date: Thu, 18 Dec 2025 08:14:53 +0100 Subject: [PATCH 5/8] getting rid of damn ai --- src/server/core/ConnectionAbstract.java | 6 +-- src/server/core/Server.java | 56 +++++++++++++++---------- src/server/module/WebModule.java | 7 ---- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/server/core/ConnectionAbstract.java b/src/server/core/ConnectionAbstract.java index f56d058..15bcc06 100644 --- a/src/server/core/ConnectionAbstract.java +++ b/src/server/core/ConnectionAbstract.java @@ -21,10 +21,10 @@ public abstract class ConnectionAbstract implements Runnable, Connection { protected byte[] frame = new byte[10]; protected String response; protected String request; - protected boolean close = false; + protected volatile boolean close = false; protected int instanceNo; - protected boolean stop = false; - protected java.net.Socket client; + protected volatile boolean stop = false; + protected Socket client; protected ServerSocket serverSocket; protected int port; diff --git a/src/server/core/Server.java b/src/server/core/Server.java index d9ec6d5..fadd8bc 100644 --- a/src/server/core/Server.java +++ b/src/server/core/Server.java @@ -1,11 +1,8 @@ package server.core; import server.config.*; +import server.module.*; import server.utils.FileUtils; - -import java.util.logging.Logger; -// import java.util.logging.Level; // unused - import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; @@ -14,15 +11,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.logging.Level; - -import server.module.*; +import java.util.logging.Logger; /** * @author andrzej.salamon@gmail.com */ public final class Server extends Thread { - private static final Logger LOGGER = Logger.getLogger(Server.class.getName()); +// private static final Logger LOGGER = Logger.getLogger(Server.class.getName()); private static final String ERR_PORT_PREFIX = "failed listening on port: "; private static final String FILE_CONFIG_SERVER_PROPS = "server.properties"; private static final String DIR_CONFIG = "config"; @@ -41,7 +37,7 @@ public enum MODULES { private ServerSocket serverWeb = null; // thread-safe list wrapper - private final List connections = Collections.synchronizedList(new ArrayList()); + private final List connections = new ArrayList(); // flags used across threads private volatile boolean running = false; @@ -64,13 +60,16 @@ public Server() { setServerProperties( FileUtils.loadServerProperties(DIR_CONFIG + FileUtils.FILE_SEPARATOR + FILE_CONFIG_SERVER_PROPS)); } catch (IOException e) { - LOGGER.log(Level.SEVERE, "No configuration found: {0}", e.getMessage()); + e.printStackTrace(); +// LOGGER.log(Level.SEVERE, "No configuration found: {0}", e.getMessage()); + System.err.println("No configuration found"); startFailed = true; System.exit(-1); } if (getSocketPort() < 1 || getWebsocketPort() < 1 || getWebPort() < 1) { - LOGGER.severe("Invalid port configuration. Ports must be greater than 0."); +// LOGGER.severe("Invalid port configuration. Ports must be greater than 0."); + System.err.println("Invalid port number"); startFailed = true; System.exit(-1); } @@ -91,8 +90,9 @@ private void configureModule(String socketEnabled, int socketPort, MODULES modul try { setupModule(module, socketPort); } catch (IOException e) { - LOGGER.log(Level.SEVERE, ERR_PORT_PREFIX + FORMAT_PARAM_LOGGER, - new Object[] { socketPort, e.getMessage() }); +// LOGGER.log(Level.SEVERE, ERR_PORT_PREFIX + FORMAT_PARAM_LOGGER, +// new Object[] { socketPort, e.getMessage() }); + System.err.println("Failed to configure module: " + e.getMessage()); startFailed = true; } } @@ -116,7 +116,8 @@ private void setupModule(MODULES module, int socketPort) throws IOException { addWebModule(); break; default: - LOGGER.severe("Unknown module type"); + System.err.println("Unknown module: " + module); +// LOGGER.severe("Unknown module type"); break; } } @@ -176,14 +177,17 @@ private void startModules() { } for (SocketConnection conn : connections) { try { - LOGGER.log(Level.INFO, "Starting module: {0} at port {1}", - new Object[] { conn.getClass().getSimpleName(), conn.getPort() }); +// LOGGER.log(Level.INFO, "Starting module: {0} at port {1}", +// new Object[] { conn.getClass().getSimpleName(), conn.getPort() }); + System.out.println("Starting module: " + conn.getClass().getSimpleName() + " at port " + conn.getPort()); conn.start(); } catch (IllegalThreadStateException e) { // already started or cannot start; log and continue - LOGGER.log(Level.SEVERE, "module start failed: {0}", e.getMessage()); +// LOGGER.log(Level.SEVERE, "module start failed: {0}", e.getMessage()); + System.err.println("module start failed: " + e.getMessage()); } catch (Exception e) { - LOGGER.log(Level.SEVERE, "unexpected module start error: {0}", e.getMessage()); +// LOGGER.log(Level.SEVERE, "unexpected module start error: {0}", e.getMessage()); + System.err.println("unexpected module start error: " + e.getMessage()); } } } @@ -198,7 +202,8 @@ private void stopModules() { try { conn.stop(); } catch (Exception e) { - LOGGER.log(Level.SEVERE, "module stop failed: {0}", e.getMessage()); +// LOGGER.log(Level.SEVERE, "module stop failed: {0}", e.getMessage()); + System.err.println("unexpected module stop error: " + e.getMessage()); } } } @@ -215,8 +220,10 @@ public static void setServerProperties(ServerProperties config) { @Override @SuppressWarnings("unused") public void run() { - LOGGER.info("Andrew (Web)Socket(s) Server v. 1.1"); - LOGGER.log(Level.INFO, "Started at IP: {0}", IP); +// LOGGER.info("Andrew (Web)Socket(s) Server v. 1.1"); + System.out.println("Andrew (Web)Socket(s) Server v. 1.1"); +// LOGGER.log(Level.INFO, "Started at IP: {0}", IP); + System.out.println("Started at IP: " + IP); startModules(); running = true; @@ -224,7 +231,8 @@ public void run() { try { Thread.sleep(1000); // sleep server for a while } catch (InterruptedException e) { - LOGGER.log(Level.WARNING, "InterruptedException: {0}", e.getMessage()); +// LOGGER.log(Level.WARNING, "InterruptedException: {0}", e.getMessage()); + System.err.println("Server sleep interrupted: " + e.getMessage()); // restore interrupted status and exit loop Thread.currentThread().interrupt(); running = false; @@ -245,7 +253,8 @@ private static String getIp() { InetAddress addr = InetAddress.getLocalHost(); return addr.getHostAddress(); } catch (UnknownHostException e) { - LOGGER.log(Level.WARNING, "UnknownHostException: {0}", e.getMessage()); +// LOGGER.log(Level.WARNING, "UnknownHostException: {0}", e.getMessage()); + System.err.println("Unable to get IP address UnknownHostException: " + e.getMessage()); return ""; } } @@ -284,7 +293,8 @@ private void closeQuietly(ServerSocket s) { try { s.close(); } catch (IOException e) { - LOGGER.log(Level.WARNING, "IOException closing socket: {0}", e.getMessage()); +// LOGGER.log(Level.WARNING, "IOException closing socket: {0}", e.getMessage()); + System.err.println("Unable to close server socket: " + e.getMessage()); // swallow - best effort close } } diff --git a/src/server/module/WebModule.java b/src/server/module/WebModule.java index ff6a843..999cb98 100644 --- a/src/server/module/WebModule.java +++ b/src/server/module/WebModule.java @@ -36,13 +36,6 @@ public void run() { flushOutputStream(); closeOutpInputStreams(); getClient().close(); -// try { -//// out.close(); -//// in.close(); -// client.close(); -// } catch (IOException e) { -// // e.printStackTrace(); -// } } catch (Exception e) { e.printStackTrace(); } From 6d14946c40fd7fefc4532af52f2ca0de2cd101be Mon Sep 17 00:00:00 2001 From: wizard Date: Thu, 18 Dec 2025 08:17:06 +0100 Subject: [PATCH 6/8] getting rid of damn ai --- src/server/core/Server.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/server/core/Server.java b/src/server/core/Server.java index fadd8bc..e982356 100644 --- a/src/server/core/Server.java +++ b/src/server/core/Server.java @@ -9,16 +9,12 @@ import java.net.UnknownHostException; import java.util.List; import java.util.ArrayList; -import java.util.Collections; -import java.util.logging.Level; -import java.util.logging.Logger; /** * @author andrzej.salamon@gmail.com */ public final class Server extends Thread { -// private static final Logger LOGGER = Logger.getLogger(Server.class.getName()); private static final String ERR_PORT_PREFIX = "failed listening on port: "; private static final String FILE_CONFIG_SERVER_PROPS = "server.properties"; private static final String DIR_CONFIG = "config"; @@ -117,7 +113,6 @@ private void setupModule(MODULES module, int socketPort) throws IOException { break; default: System.err.println("Unknown module: " + module); -// LOGGER.severe("Unknown module type"); break; } } @@ -177,8 +172,6 @@ private void startModules() { } for (SocketConnection conn : connections) { try { -// LOGGER.log(Level.INFO, "Starting module: {0} at port {1}", -// new Object[] { conn.getClass().getSimpleName(), conn.getPort() }); System.out.println("Starting module: " + conn.getClass().getSimpleName() + " at port " + conn.getPort()); conn.start(); } catch (IllegalThreadStateException e) { @@ -220,9 +213,7 @@ public static void setServerProperties(ServerProperties config) { @Override @SuppressWarnings("unused") public void run() { -// LOGGER.info("Andrew (Web)Socket(s) Server v. 1.1"); System.out.println("Andrew (Web)Socket(s) Server v. 1.1"); -// LOGGER.log(Level.INFO, "Started at IP: {0}", IP); System.out.println("Started at IP: " + IP); startModules(); @@ -231,7 +222,6 @@ public void run() { try { Thread.sleep(1000); // sleep server for a while } catch (InterruptedException e) { -// LOGGER.log(Level.WARNING, "InterruptedException: {0}", e.getMessage()); System.err.println("Server sleep interrupted: " + e.getMessage()); // restore interrupted status and exit loop Thread.currentThread().interrupt(); @@ -253,7 +243,6 @@ private static String getIp() { InetAddress addr = InetAddress.getLocalHost(); return addr.getHostAddress(); } catch (UnknownHostException e) { -// LOGGER.log(Level.WARNING, "UnknownHostException: {0}", e.getMessage()); System.err.println("Unable to get IP address UnknownHostException: " + e.getMessage()); return ""; } @@ -293,7 +282,6 @@ private void closeQuietly(ServerSocket s) { try { s.close(); } catch (IOException e) { -// LOGGER.log(Level.WARNING, "IOException closing socket: {0}", e.getMessage()); System.err.println("Unable to close server socket: " + e.getMessage()); // swallow - best effort close } From db2ce132385773b7425a2a9723072ec5884d779a Mon Sep 17 00:00:00 2001 From: wizard Date: Sun, 21 Dec 2025 13:19:57 +0100 Subject: [PATCH 7/8] simple http listeneres , refactoring etc --- README.md | 2 + src/example/ExampleHttpListener.java | 47 +++++++++++++++++ src/server/core/Connection.java | 2 +- src/server/core/ConnectionAbstract.java | 25 +++++---- src/server/core/HttpMethod.java | 46 +++++++++++++++- src/server/core/Listener.java | 20 +++++-- src/server/core/Server.java | 52 +++++++++---------- .../connection/WebConnectionAbstract.java | 3 ++ .../WebSocketConnectionAbstract.java | 3 +- .../core/listener/HttpMethodListener.java | 49 +++++++++++++++-- src/server/module/WebModule.java | 39 ++++++++++++-- 11 files changed, 234 insertions(+), 54 deletions(-) create mode 100644 src/example/ExampleHttpListener.java diff --git a/README.md b/README.md index b7a7ea0..3ff8e56 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,5 @@ Java socket server. Currently Connection plugin done for handling WebSocket conn WebSocket server is able to receive, read and send handshake also read/send data from/to client. some code snippets refactored from stackoverflow and mozilla.org + +this stuff should work on Java 1.2 and higher diff --git a/src/example/ExampleHttpListener.java b/src/example/ExampleHttpListener.java new file mode 100644 index 0000000..e8cc535 --- /dev/null +++ b/src/example/ExampleHttpListener.java @@ -0,0 +1,47 @@ +package example; + +import server.core.listener.HttpMethodListener; +import server.module.WebModule; + +public class ExampleHttpListener extends WebModule { + public ExampleHttpListener() { + super(); + setRoot("example"); + + addUriListener("GET /" + this.getRoot() + "/test", new HttpMethodListener(this) { + @Override + public void onBeforeReceive(Object message) { + System.out.println("Received request for /example: " + message); + } + + @Override + public void onAfterReceive(Object message) { + ExampleHttpListener thisModule = (ExampleHttpListener) getContext(); + thisModule.test((String) message); + System.out.println("Finished processing request for /example: " + message); + } + }); + } + + public void test(String test) { + } + // public static void main(String[] args) { +// HttpMethodListener listener = new HttpMethodListener() { +// @Override +// public void onBeforeReceive(Object message) { +// System.out.println("Before receiving: " + message); +// } +// +// @Override +// public void onAfterReceive(Object message) { +// System.out.println("After receiving: " + message); +// } +// }; +// +// // Simulate receiving a message +// String simulatedMessage = "GET /index.html HTTP/1.1"; +// listener.onBeforeReceive(simulatedMessage); +// // Here would be the logic to process the message +// listener.onAfterReceive(simulatedMessage); +// } +} diff --git a/src/server/core/Connection.java b/src/server/core/Connection.java index 9a07e70..6a890de 100644 --- a/src/server/core/Connection.java +++ b/src/server/core/Connection.java @@ -7,7 +7,7 @@ */ public interface Connection { void start(); - void stop(); + void stop() throws IOException; void receive() throws IOException; void broadcast() throws IOException; void broadcast(String data) throws IOException; diff --git a/src/server/core/ConnectionAbstract.java b/src/server/core/ConnectionAbstract.java index 15bcc06..db0ef67 100644 --- a/src/server/core/ConnectionAbstract.java +++ b/src/server/core/ConnectionAbstract.java @@ -12,7 +12,7 @@ public abstract class ConnectionAbstract implements Runnable, Connection { protected static int counter; protected final Thread thread; -// protected ObjectOutputStream out; + // protected ObjectOutputStream out; // protected ObjectInputStream in; protected OutputStream outputStream; protected InputStream inputStream; @@ -21,9 +21,9 @@ public abstract class ConnectionAbstract implements Runnable, Connection { protected byte[] frame = new byte[10]; protected String response; protected String request; - protected volatile boolean close = false; + protected boolean close = false; protected int instanceNo; - protected volatile boolean stop = false; + protected boolean stop = false; protected Socket client; protected ServerSocket serverSocket; protected int port; @@ -38,6 +38,14 @@ protected ConnectionAbstract(ServerSocket serverSocket) { } + //for child classes + protected ConnectionAbstract() { + this.instanceNo = getCounter(); + incrementCounter(); + this.thread = new Thread(this, MODULE_NAME + instanceNo); + + } + public int getPort() { return port; } @@ -77,12 +85,13 @@ public void start() { } @Override - public void stop() { + public void stop() throws IOException { // getThread().stop(); getThread().interrupt(); stop = true; decrementCounter(); instanceNo = -1; + client.close(); } public void processStreamBinary(Socket client) { @@ -117,13 +126,7 @@ public void processStream(Socket client) { inputStream = getClient().getInputStream(); } catch (IOException e) { e.printStackTrace(); - } /*finally { - try { //try to close gracefully - client.close(); - } catch (IOException e) { - e.printStackTrace(); - } - }*/ + } } public void processStreamBinary() { diff --git a/src/server/core/HttpMethod.java b/src/server/core/HttpMethod.java index 59dcc5a..8253085 100644 --- a/src/server/core/HttpMethod.java +++ b/src/server/core/HttpMethod.java @@ -7,5 +7,49 @@ public enum HttpMethod { DELETE, HEAD, OPTIONS, - PATCH + PATCH; + + public static HttpMethod fromString(String method) { + for (HttpMethod httpMethod : HttpMethod.values()) { + if (httpMethod.name().equalsIgnoreCase(method)) { + return httpMethod; + } + } + throw new IllegalArgumentException("Unknown HTTP method: " + method); + } + + public static boolean isGet(String request) { + int indexOf = request.indexOf(GET.toString()); + return indexOf != -1; + } + + public static boolean isPost(String request) { + int indexOf = request.indexOf(POST.toString()); + return indexOf != -1; + } + + public static boolean isPut(String request) { + int indexOf = request.indexOf(PUT.toString()); + return indexOf != -1; + } + + public static boolean isDelete(String request) { + int indexOf = request.indexOf(DELETE.toString()); + return indexOf != -1; + } + + public static boolean isHead(String request) { + int indexOf = request.indexOf(HEAD.toString()); + return indexOf != -1; + } + + public static boolean isOptions(String request) { + int indexOf = request.indexOf(OPTIONS.toString()); + return indexOf != -1; + } + + public static boolean isPatch(String request) { + int indexOf = request.indexOf(PATCH.toString()); + return indexOf != -1; + } } diff --git a/src/server/core/Listener.java b/src/server/core/Listener.java index 4a3bd27..7009cb5 100644 --- a/src/server/core/Listener.java +++ b/src/server/core/Listener.java @@ -1,8 +1,18 @@ package server.core; -public interface Listener { - void onReceive(T message); - void onBroadcast(T message); - T onBroadcast(); - T onReceive(); +public interface Listener { + public enum WHEN { + BEFORE, + AFTER + } + WHEN defaultWhen = WHEN.AFTER; + + void onBeforeReceive(Object message); + void onBeforeBroadcast(Object message); + Object onBeforeBroadcast(); + Object onBeforeReceive(); + void onAfterReceive(Object message); + void onAfterBroadcast(Object message); + Object onAfterBroadcast(); + Object onAfterReceive(); } diff --git a/src/server/core/Server.java b/src/server/core/Server.java index e982356..ef2f80d 100644 --- a/src/server/core/Server.java +++ b/src/server/core/Server.java @@ -3,6 +3,7 @@ import server.config.*; import server.module.*; import server.utils.FileUtils; + import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; @@ -25,8 +26,8 @@ public enum MODULES { SOCKET, WEBSOCKET, WEB - } + private static ServerProperties serverProperties; private ServerSocket serverSocket = null; private ServerSocket serverWebSocket = null; @@ -36,19 +37,10 @@ public enum MODULES { private final List connections = new ArrayList(); // flags used across threads - private volatile boolean running = false; - private volatile boolean stop = false; - - public boolean isExitOnFail() { - return exitOnFail; - } - - public void setExitOnFail(boolean exitOnFail) { - this.exitOnFail = exitOnFail; - } - - private volatile boolean exitOnFail = true; - private volatile boolean startFailed = false; + private static boolean running = false; + private static boolean stop = false; + private static boolean exitOnFail = true; + private static boolean startFailed = false; public Server() { // we are not using nio because we want to have it synchronous @@ -81,6 +73,14 @@ public Server() { this.start(); } + public boolean isExitOnFail() { + return exitOnFail; + } + + public void setExitOnFail(boolean exitOnFail) { + Server.exitOnFail = exitOnFail; + } + private void configureModule(String socketEnabled, int socketPort, MODULES module) { if (isEnabled(socketEnabled)) try { @@ -160,8 +160,10 @@ public void addModule(SocketConnection socketConnection) { if (socketConnection == null) { return; } - if (!connections.contains(socketConnection)) { - connections.add(socketConnection); + synchronized (connections) { + if (!connections.contains(socketConnection)) { + connections.add(socketConnection); + } } } @@ -233,9 +235,9 @@ public void run() { return; } } - // ensure cleanup in case loop exits - stopModules(); - stopServer(); +// // ensure cleanup in case loop exits +// stopModules(); +// stopServer(); } private static String getIp() { @@ -270,15 +272,13 @@ public ServerSocket getServerWebSocket() { public void stopServer() { running = false; // close server sockets quietly - closeQuietly(serverSocket); - closeQuietly(serverWebSocket); - closeQuietly(serverWeb); + closeServerSocket(serverSocket); + closeServerSocket(serverWebSocket); + closeServerSocket(serverWeb); } - private void closeQuietly(ServerSocket s) { - if (s == null) { - return; - } + private void closeServerSocket(ServerSocket s) { + if (s == null) return; try { s.close(); } catch (IOException e) { diff --git a/src/server/core/connection/WebConnectionAbstract.java b/src/server/core/connection/WebConnectionAbstract.java index 37050ab..ef9a292 100644 --- a/src/server/core/connection/WebConnectionAbstract.java +++ b/src/server/core/connection/WebConnectionAbstract.java @@ -11,4 +11,7 @@ protected WebConnectionAbstract(ServerSocket serverSocket) { super(serverSocket); } + public WebConnectionAbstract() { + super(); + } } diff --git a/src/server/core/connection/WebSocketConnectionAbstract.java b/src/server/core/connection/WebSocketConnectionAbstract.java index 2d0095c..02442ac 100644 --- a/src/server/core/connection/WebSocketConnectionAbstract.java +++ b/src/server/core/connection/WebSocketConnectionAbstract.java @@ -59,8 +59,7 @@ private Matcher setSecWebSocketKey() { } public boolean isGet() { - Matcher get = Pattern.compile("^"+ HttpMethod.GET).matcher(request); - return get.find(); + return HttpMethod.isGet(request); } public void receive() throws IOException { diff --git a/src/server/core/listener/HttpMethodListener.java b/src/server/core/listener/HttpMethodListener.java index 12e0aff..e2a109c 100644 --- a/src/server/core/listener/HttpMethodListener.java +++ b/src/server/core/listener/HttpMethodListener.java @@ -1,26 +1,67 @@ package server.core.listener; +import server.core.HttpMethod; import server.core.Listener; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + public class HttpMethodListener implements Listener { + private Map uris = new HashMap<>(); + private Object context; + public HttpMethodListener(Object context) { + this.context = context; + } + + @Override + public void onBeforeReceive(Object message) { + + } + + @Override + public void onBeforeBroadcast(Object message) { + + } + @Override - public void onReceive(Object message) { + public Object onBeforeBroadcast() { + return null; + } + @Override + public Object onBeforeReceive() { + return null; } @Override - public void onBroadcast(Object message) { + public void onAfterReceive(Object message) { } @Override - public Object onBroadcast() { + public void onAfterBroadcast(Object message) { + + } + + @Override + public Object onAfterBroadcast() { return null; } @Override - public Object onReceive() { + public Object onAfterReceive() { return null; } + public boolean addUriListener(String uri, HttpMethodListener callback) { + uris.put(uri, callback); + return true; + } + + public Object getContext() { + return context; + } } diff --git a/src/server/module/WebModule.java b/src/server/module/WebModule.java index 999cb98..f3c9a99 100644 --- a/src/server/module/WebModule.java +++ b/src/server/module/WebModule.java @@ -1,7 +1,9 @@ package server.module; +import server.core.Listener; import server.core.Server; import server.core.connection.WebConnectionAbstract; +import server.core.listener.HttpMethodListener; import java.io.BufferedReader; import java.io.IOException; @@ -18,10 +20,18 @@ public class WebModule extends WebConnectionAbstract { private PrintWriter printWriter; + private HttpMethodListener httpMethodListener = new HttpMethodListener(this); + private String signature; + private String root; + public WebModule(ServerSocket serverSocket) { super(serverSocket); } + public WebModule() { + super(); + } + @Override public String getId() { return MODULE_NAME; @@ -49,13 +59,14 @@ private void closeOutpInputStreams() throws IOException { @Override public void receive() throws IOException { - java.util.Scanner in = new java.util.Scanner(inputStream); StringBuilder requestBuilder = new StringBuilder(); - String line; - while (in.hasNextLine() && !(line = in.nextLine()).isEmpty()) { + BufferedReader in = new BufferedReader(new InputStreamReader(inputStream)); + String line = in.readLine(); + signature = line; + requestBuilder.append(line); + while ((line = in.readLine()) != null) { requestBuilder.append(line).append("\r\n"); } - request = requestBuilder.toString(); System.out.println("Received request:\n" + request); } @@ -83,4 +94,24 @@ public void broadcast(String data) throws IOException { printWriter.println(data); flushPrintWriter(); } + + public String getUri() { + String[] parts = signature.split(" "); + if (parts.length >= 2) { + return parts[1]; + } + return null; + } + + public boolean addUriListener(String uri, HttpMethodListener callback) { + return httpMethodListener.addUriListener(uri, callback); + } + + public String getRoot() { + return root; + } + + public void setRoot(String root) { + this.root = root; + } } From 99d83cd6bb909bdcc338c7173f1e860dceaf9312 Mon Sep 17 00:00:00 2001 From: wizard Date: Sun, 21 Dec 2025 14:42:08 +0100 Subject: [PATCH 8/8] added example listener, rf --- src/example/ExampleHttpListener.java | 27 +++++-- src/server/core/ConnectionAbstract.java | 16 ++++ src/server/core/Listener.java | 10 --- .../core/listener/HttpMethodListener.java | 40 ++-------- src/server/module/WebModule.java | 76 ++++++++++++++++--- 5 files changed, 108 insertions(+), 61 deletions(-) diff --git a/src/example/ExampleHttpListener.java b/src/example/ExampleHttpListener.java index e8cc535..cdd42d0 100644 --- a/src/example/ExampleHttpListener.java +++ b/src/example/ExampleHttpListener.java @@ -6,24 +6,39 @@ public class ExampleHttpListener extends WebModule { public ExampleHttpListener() { super(); - setRoot("example"); - - addUriListener("GET /" + this.getRoot() + "/test", new HttpMethodListener(this) { + setRoot("/example"); + registerListener("GET /test", new HttpMethodListener() { @Override public void onBeforeReceive(Object message) { System.out.println("Received request for /example: " + message); } @Override - public void onAfterReceive(Object message) { + public void onAfterReceive(Object request) { + //do something with request here ExampleHttpListener thisModule = (ExampleHttpListener) getContext(); - thisModule.test((String) message); - System.out.println("Finished processing request for /example: " + message); + thisModule.test((String) request); //call it from context + //or call it directly + test("test request from /example"); + System.out.println("Finished processing request for /example: " + request); + } + + @Override + public void onBeforeBroadcast(Object message) { + //add your response here + setResponse("test response from /example"); + System.out.println("About to broadcast response for /example: " + message); + } + @Override + public void onAfterBroadcast(Object message) { + System.out.println("Finished broadcasting response for /example: " + message); } }); } public void test(String test) { + //do something with data + setResponse("test response from /example"); } // public static void main(String[] args) { // HttpMethodListener listener = new HttpMethodListener() { diff --git a/src/server/core/ConnectionAbstract.java b/src/server/core/ConnectionAbstract.java index db0ef67..0fbb957 100644 --- a/src/server/core/ConnectionAbstract.java +++ b/src/server/core/ConnectionAbstract.java @@ -149,4 +149,20 @@ protected void closeInputStream() throws IOException { protected void closeOutputStream() throws IOException { outputStream.close(); } + + public String getResponseAsString() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + + public String getRequestAsString() { + return request; + } + + public void setRequest(String request) { + this.request = request; + } } diff --git a/src/server/core/Listener.java b/src/server/core/Listener.java index 7009cb5..3f5f9d9 100644 --- a/src/server/core/Listener.java +++ b/src/server/core/Listener.java @@ -1,18 +1,8 @@ package server.core; public interface Listener { - public enum WHEN { - BEFORE, - AFTER - } - WHEN defaultWhen = WHEN.AFTER; - void onBeforeReceive(Object message); void onBeforeBroadcast(Object message); - Object onBeforeBroadcast(); - Object onBeforeReceive(); void onAfterReceive(Object message); void onAfterBroadcast(Object message); - Object onAfterBroadcast(); - Object onAfterReceive(); } diff --git a/src/server/core/listener/HttpMethodListener.java b/src/server/core/listener/HttpMethodListener.java index e2a109c..e470264 100644 --- a/src/server/core/listener/HttpMethodListener.java +++ b/src/server/core/listener/HttpMethodListener.java @@ -1,19 +1,10 @@ package server.core.listener; -import server.core.HttpMethod; import server.core.Listener; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - public class HttpMethodListener implements Listener { - private Map uris = new HashMap<>(); private Object context; - public HttpMethodListener(Object context) { - this.context = context; + public HttpMethodListener() { } @Override @@ -26,16 +17,6 @@ public void onBeforeBroadcast(Object message) { } - @Override - public Object onBeforeBroadcast() { - return null; - } - - @Override - public Object onBeforeReceive() { - return null; - } - @Override public void onAfterReceive(Object message) { @@ -46,22 +27,11 @@ public void onAfterBroadcast(Object message) { } - @Override - public Object onAfterBroadcast() { - return null; - } - - @Override - public Object onAfterReceive() { - return null; - } - - public boolean addUriListener(String uri, HttpMethodListener callback) { - uris.put(uri, callback); - return true; - } - public Object getContext() { return context; } + + public void setContext(Object context) { + this.context = context; + } } diff --git a/src/server/module/WebModule.java b/src/server/module/WebModule.java index f3c9a99..89790c7 100644 --- a/src/server/module/WebModule.java +++ b/src/server/module/WebModule.java @@ -1,6 +1,6 @@ package server.module; -import server.core.Listener; +import server.core.HttpMethod; import server.core.Server; import server.core.connection.WebConnectionAbstract; import server.core.listener.HttpMethodListener; @@ -10,6 +10,8 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; +import java.util.HashMap; +import java.util.Map; /** * @author andrzej.salamon@gmail.com @@ -19,10 +21,12 @@ public class WebModule extends WebConnectionAbstract { public static final Server.MODULES MODULE_TYPE = Server.MODULES.WEB; private PrintWriter printWriter; - - private HttpMethodListener httpMethodListener = new HttpMethodListener(this); + private Map listeners = new HashMap(); private String signature; private String root; + private String method; + private String uri; + private String uriWithMethod; public WebModule(ServerSocket serverSocket) { super(serverSocket); @@ -42,6 +46,7 @@ public void run() { try { processStream(); receive(); + setRequest("

Default Response

"); broadcast(); flushOutputStream(); closeOutpInputStreams(); @@ -59,6 +64,7 @@ private void closeOutpInputStreams() throws IOException { @Override public void receive() throws IOException { + callBeforeReceive(uriWithMethod); StringBuilder requestBuilder = new StringBuilder(); BufferedReader in = new BufferedReader(new InputStreamReader(inputStream)); String line = in.readLine(); @@ -67,17 +73,41 @@ public void receive() throws IOException { while ((line = in.readLine()) != null) { requestBuilder.append(line).append("\r\n"); } + parseSignature(); request = requestBuilder.toString(); + callAfterReceive(uriWithMethod); System.out.println("Received request:\n" + request); } + private void callBeforeReceive(String uriWithMethod) { + checkListener(uriWithMethod); + HttpMethodListener callback = listeners.get(uri); + callback.setContext(this); + callback.onBeforeReceive(request); + callback.setContext(null); //lets clear context after use + } + + private void checkListener(String uriWithMethod) { + if (!listeners.containsKey(uriWithMethod)) { + throw new RuntimeException("No listener for uriWithMethod: " + uriWithMethod); + } + } + + private void callAfterReceive(String uriWithMethod) { + checkListener(uriWithMethod); + HttpMethodListener callback = listeners.get(uri); + callback.setContext(this); //current module that extends WebModule + callback.onAfterReceive(request); + callback.setContext(null); //lets clear context after use + } + @Override - public void broadcast() throws IOException { + public void broadcast() { printWriter = new PrintWriter(outputStream, true); printWriter.println("HTTP/1.1 200 OK"); printWriter.println("Content-Type: text/html"); printWriter.println(); - printWriter.println("

Hello, World!

"); + printWriter.println(getResponseAsString()); flushPrintWriter(); } @@ -87,24 +117,50 @@ private void flushPrintWriter() { @Override public void broadcast(String data) throws IOException { + callBeforeBrodcast(uriWithMethod, data); printWriter = new PrintWriter(outputStream, true); printWriter.println("HTTP/1.1 200 OK"); printWriter.println("Content-Type: text/html"); printWriter.println(); printWriter.println(data); flushPrintWriter(); + callAfterBrodcast(uriWithMethod, data); } - public String getUri() { + private void callAfterBrodcast(String uriWithMethod, String data) { + checkListener(uriWithMethod); + HttpMethodListener callback = listeners.get(uri); + callback.setContext(this); //current module that extends WebModule + callback.onAfterBroadcast(data); + callback.setContext(null); //lets clear context after use + } + + private void callBeforeBrodcast(String uriWithMethod, String data) { + checkListener(uriWithMethod); + HttpMethodListener callback = listeners.get(uri); + callback.setContext(this); //current module that extends WebModule + callback.onBeforeBroadcast(data); + callback.setContext(null); //lets clear context after use + } + + public void parseSignature() { String[] parts = signature.split(" "); if (parts.length >= 2) { - return parts[1]; + this.method = parts[0]; + this.uri = parts[1]; + this.uriWithMethod = method + " " + getRoot() + uri; + } + } + + public void registerListener(String uri, HttpMethodListener callback) { + if (listeners.containsKey(uri)) { + throw new IllegalArgumentException("Listener for URI already registered: " + uri); } - return null; + listeners.put(uri, callback); } - public boolean addUriListener(String uri, HttpMethodListener callback) { - return httpMethodListener.addUriListener(uri, callback); + public void registerListener(HttpMethod method, String uri, HttpMethodListener callback) { + registerListener(method.toString() + " " + uri, callback); } public String getRoot() {