Tuesday, July 22, 2025

Java Control Run

# Java Server Application with Start/Stop Controls

Here's a complete implementation of a Java server application with proper start/stop functionality that can be controlled both programmatically and via a web interface:

## Complete Server Application with Controls

```java
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;

import java.io.*;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ServerApplication {
    private static HttpServer server;
    private static ExecutorService executor;
    private static final int PORT = 8080;
    private static boolean isRunning = false;

    public static void main(String[] args) {
        // Register shutdown hook
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            stopServer();
            System.out.println("Server stopped during shutdown");
        }));

        // Start the server
        startServer();
        
        // Keep the main thread alive
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }

    public static synchronized void startServer() {
        if (isRunning) {
            System.out.println("Server is already running");
            return;
        }

        try {
            server = HttpServer.create(new InetSocketAddress(PORT), 0);
            executor = Executors.newFixedThreadPool(10);
            server.setExecutor(executor);

            // Add context for server control
            server.createContext("/control", new ControlHandler());
            
            // Add context for status check
            server.createContext("/status", exchange -> {
                String response = "Server is " + (isRunning ? "running" : "stopped");
                exchange.sendResponseHeaders(200, response.length());
                try (OutputStream os = exchange.getResponseBody()) {
                    os.write(response.getBytes());
                }
            });

            // Add context for main page
            server.createContext("/", exchange -> {
                String html = "<!DOCTYPE html>\n" +
                        "<html>\n" +
                        "<head>\n" +
                        "    <title>Server Control Panel</title>\n" +
                        "    <style>\n" +
                        "        body { font-family: Arial, sans-serif; margin: 40px; }\n" +
                        "        .controls { margin: 20px 0; }\n" +
                        "        button { padding: 8px 15px; margin-right: 10px; }\n" +
                        "        .status { padding: 10px; margin: 10px 0; }\n" +
                        "        .running { background-color: #dff0d8; }\n" +
                        "        .stopped { background-color: #f2dede; }\n" +
                        "    </style>\n" +
                        "    <script>\n" +
                        "        function updateStatus() {\n" +
                        "            fetch('/status')\n" +
                        "                .then(response => response.text())\n" +
                        "                .then(text => {\n" +
                        "                    const statusDiv = document.getElementById('status');\n" +
                        "                    statusDiv.textContent = text;\n" +
                        "                    statusDiv.className = text.includes('running') ? 'status running' : 'status stopped';\n" +
                        "                });\n" +
                        "        }\n" +
                        "        \n" +
                        "        function sendCommand(action) {\n" +
                        "            fetch('/control?action=' + action)\n" +
                        "                .then(() => updateStatus())\n" +
                        "                .catch(err => console.error('Error:', err));\n" +
                        "        }\n" +
                        "        \n" +
                        "        // Update status every 2 seconds\n" +
                        "        setInterval(updateStatus, 2000);\n" +
                        "        window.onload = updateStatus;\n" +
                        "    </script>\n" +
                        "</head>\n" +
                        "<body>\n" +
                        "    <h1>Server Control Panel</h1>\n" +
                        "    <div id=\"status\" class=\"status\">Checking status...</div>\n" +
                        "    <div class=\"controls\">\n" +
                        "        <button onclick=\"sendCommand('start')\">Start Server</button>\n" +
                        "        <button onclick=\"sendCommand('stop')\">Stop Server</button>\n" +
                        "        <button onclick=\"sendCommand('restart')\">Restart Server</button>\n" +
                        "    </div>\n" +
                        "</body>\n" +
                        "</html>";

                exchange.getResponseHeaders().set("Content-Type", "text/html");
                exchange.sendResponseHeaders(200, html.length());
                try (OutputStream os = exchange.getResponseBody()) {
                    os.write(html.getBytes());
                }
            });

            server.start();
            isRunning = true;
            System.out.println("Server started on port " + PORT);
            System.out.println("Control panel available at: http://localhost:" + PORT);
        } catch (IOException e) {
            System.err.println("Failed to start server: " + e.getMessage());
        }
    }

    public static synchronized void stopServer() {
        if (!isRunning) {
            System.out.println("Server is not running");
            return;
        }

        if (server != null) {
            server.stop(1); // Delay of 1 second for graceful shutdown
        }
        if (executor != null) {
            executor.shutdownNow();
        }
        isRunning = false;
        System.out.println("Server stopped");
    }

    static class ControlHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String action = exchange.getRequestURI().getQuery().split("=")[1];
            String response;

            switch (action.toLowerCase()) {
                case "start":
                    startServer();
                    response = "Server started";
                    break;
                case "stop":
                    stopServer();
                    response = "Server stopped";
                    break;
                case "restart":
                    stopServer();
                    startServer();
                    response = "Server restarted";
                    break;
                default:
                    response = "Invalid action";
                    exchange.sendResponseHeaders(400, response.length());
                    try (OutputStream os = exchange.getResponseBody()) {
                        os.write(response.getBytes());
                    }
                    return;
            }

            exchange.sendResponseHeaders(200, response.length());
            try (OutputStream os = exchange.getResponseBody()) {
                os.write(response.getBytes());
            }
        }
    }
}
```

## Key Features

1. **Server Controls**:
   - Start, stop, and restart functionality
   - Synchronized methods to prevent race conditions
   - Graceful shutdown with delay

2. **Web Interface**:
   - Real-time status updates
   - Control buttons with JavaScript fetch API
   - Visual status indicators (green for running, red for stopped)

3. **API Endpoints**:
   - `/control?action=start|stop|restart` - Control the server
   - `/status` - Check server status

4. **Thread Management**:
   - Fixed thread pool for handling requests
   - Proper shutdown of executor service

5. **Error Handling**:
   - Synchronized methods to prevent concurrent modification
   - Proper resource cleanup
   - Input validation for control actions

## How to Use

1. **Run the Server**:
   ```bash
   javac ServerApplication.java
   java ServerApplication
   ```

2. **Access the Control Panel**:
   Open your browser to `http://localhost:8080`

3. **Control the Server**:
   - Use the buttons in the web interface to start, stop, or restart
   - Or make direct API calls to `/control` endpoint

4. **Check Status**:
   - View the status in the web interface
   - Or call `/status` endpoint directly

## Advanced Usage

### 1. Running as a Windows Service

Create a wrapper class for service integration:

```java
import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;

public class WindowsService implements Daemon {
    @Override
    public void init(DaemonContext context) {
        // Initialization code
    }

    @Override
    public void start() {
        ServerApplication.startServer();
    }

    @Override
    public void stop() {
        ServerApplication.stopServer();
    }

    @Override
    public void destroy() {
        // Cleanup code
    }
}
```

### 2. Adding Authentication

Secure the control endpoints:

```java
server.createContext("/control", exchange -> {
    // Basic authentication check
    String auth = exchange.getRequestHeaders().getFirst("Authorization");
    if (auth == null || !auth.equals("Basic " + Base64.getEncoder().encodeToString("admin:password".getBytes()))) {
        exchange.getResponseHeaders().set("WWW-Authenticate", "Basic");
        exchange.sendResponseHeaders(401, -1);
        return;
    }
    // Process the request
    new ControlHandler().handle(exchange);
});
```

### 3. Logging Server Events

Add logging functionality:

```java
import java.util.logging.Logger;
import java.util.logging.Level;

private static final Logger logger = Logger.getLogger(ServerApplication.class.getName());

// In your methods:
logger.log(Level.INFO, "Server started on port " + PORT);
logger.log(Level.WARNING, "Failed to start server: " + e.getMessage());
```

### 4. Configuration File

Add configuration support:

```java
import java.util.Properties;
import java.nio.file.Files;
import java.nio.file.Paths;

private static int loadPort() {
    Properties props = new Properties();
    try (InputStream in = Files.newInputStream(Paths.get("server.properties"))) {
        props.load(in);
        return Integer.parseInt(props.getProperty("server.port", "8080"));
    } catch (Exception e) {
        return 8080; // default
    }
}
```

This implementation provides a robust foundation for a controllable Java server application with both programmatic and web-based control interfaces. You can extend it further based on your specific requirements.

No comments: