/* * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
/** * Start a new server main thread, that will listen to incoming connection requests from the client, * and dispatch these on to worker threads in a thread pool, running javac.
*/ publicclass Server { private ServerSocket serverSocket; private PortFile portFile; private PortFileMonitor portFileMonitor; private IdleMonitor idleMonitor; private CompilerThreadPool compilerThreadPool;
// Set to false break accept loop final AtomicBoolean keepAcceptingRequests = new AtomicBoolean();
// For logging server internal (non request specific) errors. privatestatic LazyInitFileLog errorLog;
Server server = new Server(portFile); if (!server.start()) {
System.exit(Result.ERROR.exitCode);
} else {
System.exit(Result.OK.exitCode);
}
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
System.exit(Result.ERROR.exitCode);
}
}
privatestaticvoid initLogging() { // Under normal operation, all logging messages generated server-side // are due to compilation requests. These logging messages should // be relayed back to the requesting client rather than written to the // server log. The only messages that should be written to the server // log (in production mode) should be errors,
errorLog = new LazyInitFileLog("server.log");
Log.setLogForCurrentThread(errorLog);
Log.setLogLevel(Log.Level.ERROR); // should be set to ERROR.
// Make sure no exceptions go under the radar Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
restoreServerErrorLog();
Log.error(e);
});
// Inevitably someone will try to print messages using System.{out,err}. // Make sure this output also ends up in the log.
System.setOut(new PrintStream(new LoggingOutputStream(System.out, Log.Level.INFO, "[stdout] ")));
System.setErr(new PrintStream(new LoggingOutputStream(System.err, Log.Level.ERROR, "[stderr] ")));
}
public Server(PortFile portFile) throws FileNotFoundException { this.portFile = portFile;
}
/** * Start the daemon, unless another one is already running, in which it returns * false and exits immediately.
*/ privateboolean start() throws IOException, InterruptedException { // The port file is locked and the server port and cookie is written into it.
portFile.lock();
portFile.getValues(); if (portFile.containsPortInfo()) {
Log.debug("javacserver daemon not started because portfile exists!");
portFile.unlock(); returnfalse;
}
// At this point the server accepts connections, so it is now safe // to publish the port / cookie information
// The secret cookie shared between server and client through the port file. // Used to prevent clients from believing that they are communicating with // an old server when a new server has started and reused the same port as // an old server. long myCookie = new Random().nextLong();
portFile.setValues(serverSocket.getLocalPort(), myCookie);
portFile.unlock();
portFileMonitor = new PortFileMonitor(portFile, this::shutdownServer);
portFileMonitor.start();
compilerThreadPool = new CompilerThreadPool();
idleMonitor = new IdleMonitor(this::shutdownServer);
keepAcceptingRequests.set(true); do { try {
Socket socket = serverSocket.accept(); // Handle each incoming request in a separate thread. This is just for socket communication, // the actual compilation will be done by the threadpool. Thread requestHandler = newThread(() -> handleRequest(socket));
requestHandler.start();
} catch (SocketException se) { // Caused by serverSocket.close() and indicates shutdown
}
} while (keepAcceptingRequests.get());
Log.debug("Shutting down.");
// No more connections accepted. If any client managed to connect after // the accept() was interrupted but before the server socket is closed // here, any attempt to read or write to the socket will result in an // IOException on the client side.
// Shut down
idleMonitor.shutdown();
compilerThreadPool.shutdown();
returntrue;
}
privatevoid handleRequest(Socket socket) { try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) { try {
idleMonitor.startCall();
// Set up logging for this thread. Stream back logging messages to // client on the format "level:msg".
Log.setLogForCurrentThread(new Protocol.ProtocolLog(out));
String[] args = Protocol.readCommand(in);
// If there has been any internal errors, notify client
checkInternalErrorLog();
// Perform compilation. This will call runCompiler() on a // thread in the thread pool int exitCode = compilerThreadPool.dispatchCompilation(args);
Protocol.sendExitCode(out, exitCode);
// Check for internal errors again.
checkInternalErrorLog();
} finally {
idleMonitor.endCall();
}
} catch (Exception ex) { // Not much to be done at this point. The client side request // code will most likely throw an IOException and the // compilation will fail.
Log.error(ex);
} finally {
Log.setLogForCurrentThread(null);
}
}
publicvoid shutdownServer(String quitMsg) { if (!keepAcceptingRequests.compareAndSet(true, false)) { // Already stopped, no need to shut down again return;
}
Log.debug("Quitting: " + quitMsg);
portFileMonitor.shutdown(); // No longer any need to monitor port file
// Unpublish port before shutting down socket to minimize the number of // failed connection attempts try {
portFile.delete();
} catch (IOException | InterruptedException e) {
Log.error(e);
} try {
serverSocket.close();
} catch (IOException e) {
Log.error(e);
}
}
}
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.