# 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:
Post a Comment