com.microsoft.java.debug.plugin.internal.JavaDebugServer Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2017 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/
package com.microsoft.java.debug.plugin.internal;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.microsoft.java.debug.core.Configuration;
import com.microsoft.java.debug.core.adapter.ProtocolServer;
public class JavaDebugServer implements IDebugServer {
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
private static JavaDebugServer singletonInstance;
private ServerSocket serverSocket = null;
private boolean isStarted = false;
private ExecutorService executor = null;
private JavaDebugServer() {
try {
this.serverSocket = new ServerSocket(0, 1);
} catch (IOException e) {
logger.log(Level.SEVERE, String.format("Failed to create Java Debug Server: %s", e.toString()), e);
}
}
/**
* Gets the single instance of JavaDebugServer.
* @return the JavaDebugServer instance
*/
public static synchronized IDebugServer getInstance() {
if (singletonInstance == null) {
singletonInstance = new JavaDebugServer();
}
return singletonInstance;
}
/**
* Gets the server port.
*/
@Override
public synchronized int getPort() {
if (this.serverSocket != null) {
return this.serverSocket.getLocalPort();
}
return -1;
}
/**
* Starts the server if it's not started yet.
*/
@Override
public synchronized void start() {
if (this.serverSocket != null && !this.isStarted) {
this.isStarted = true;
this.executor = new ThreadPoolExecutor(0, 100, 30L, TimeUnit.SECONDS, new SynchronousQueue());
// Execute eventLoop in a new thread.
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
// Allow server socket to service multiple clients at the same time.
// When a request comes in, create a connection thread to process it.
// Then the server goes back to listen for new connection request.
Socket connection = serverSocket.accept();
executor.submit(createConnectionTask(connection));
} catch (IOException e) {
logger.log(Level.SEVERE, String.format("Setup socket connection exception: %s", e.toString()), e);
closeServerSocket();
// If exception occurs when waiting for new client connection, shut down the connection pool
// to make sure no new tasks are accepted. But the previously submitted tasks will continue to run.
shutdownConnectionPool(false);
return;
}
}
}
}, "Java Debug Server").start();
}
}
@Override
public synchronized void stop() {
closeServerSocket();
shutdownConnectionPool(true);
}
private synchronized void closeServerSocket() {
if (serverSocket != null) {
try {
logger.info("Close debugserver socket port " + serverSocket.getLocalPort());
serverSocket.close();
} catch (IOException e) {
logger.log(Level.SEVERE, String.format("Close ServerSocket exception: %s", e.toString()), e);
}
}
serverSocket = null;
}
private synchronized void shutdownConnectionPool(boolean now) {
if (this.executor != null) {
if (now) {
this.executor.shutdownNow();
} else {
this.executor.shutdown();
}
}
}
private Runnable createConnectionTask(Socket connection) {
return new Runnable() {
@Override
public void run() {
try {
ProtocolServer protocolServer = new ProtocolServer(connection.getInputStream(), connection.getOutputStream(),
JdtProviderContextFactory.createProviderContext());
// protocol server will dispatch request and send response in a while-loop.
protocolServer.run();
} catch (IOException e) {
logger.log(Level.SEVERE, String.format("Socket connection exception: %s", e.toString()), e);
} finally {
logger.info("Debug connection closed");
}
}
};
}
}