Я просматривал код библиотеки HAPI.
Причина описываемого вами поведения могла быть следующей.
Когда сервер запускается, они создают компонент с именем AcceptorThread
. Как следует из названия, ответственность этого потока заключается в инициализации ServerSocket
, который будет использоваться для приема входящих клиентских подключений, и их приема.
Этот поток, как и каждая Service
абстракция, предложенная API, работает в al oop следующим образом:
/**
* Runs the thread.
*
* @see java.lang.Runnable#run()
*/
public final void run() {
try {
afterStartup();
log.debug("Thread {} entering main loop", name);
while (isRunning()) {
handle();
startupLatch.countDown();
}
log.debug("Thread {} leaving main loop", name);
} catch (RuntimeException t) {
if (t.getCause() != null) {
serviceExitedWithException = t.getCause();
} else {
serviceExitedWithException = t;
}
log.warn("Thread exiting main loop due to exception:", t);
} catch (Throwable t) {
serviceExitedWithException = t;
log.warn("Thread exiting main loop due to exception:", t);
} finally {
startupLatch.countDown();
afterTermination();
}
}
Когда вы вызываете метод stopAndWait
на сервере, он также попытается остановить этот поток.
Процесс остановки в основном меняется флаг boolean
, который контролирует, будет ли компонент `` ìsRunning () '' или нет.
Как видите, хотя он устанавливает флаг в false
, вызов метода handle
в l oop все еще должен заканчиваться.
Это реализация метода AcceptorThread
handle
:
@Override
protected void handle() {
try {
Socket s = ss.accept();
socketFactory.configureNewAcceptedSocket(s);
if (!queue.offer(new AcceptedSocket(s))) {
log.error("Denied enqueuing server-side socket {}", s);
s.close();
} else
log.debug("Enqueued server-side socket {}", s);
} catch (SocketTimeoutException e) { /* OK - just timed out */
log.trace("No connection established while waiting");
} catch (IOException e) {
log.error("Error while accepting connections", e);
}
}
Как видите, метод вызывает ServerSocket.accept
, таким образом разрешая новые входящие соединения.
Чтобы отключить этот серверный сокет, мы можем вызвать close
из другого потока.
Фактически, этот процесс реализован AcceptorTread
afterTermination
метод:
@Override
protected void afterTermination() {
try {
if (ss != null && !ss.isClosed())
ss.close();
} catch (IOException e) {
log.warn("Error during stopping the thread", e);
}
}
Unfortu наконец - вы правы, API очень близко! - нет четкого способа сделать это.
Одним из возможных решений может быть реализация вашего собственного HL7Service
, назовите его MySimpleServer
, используя код SimpleServer
в качестве базовой линии и просто изменив реализация метода afterTermination
:
/**
* Close down socket
*/
@Override
protected void afterTermination() {
super.afterTermination();
// Terminate server side socket
acceptor.afterTermination();
// Terminate the acceptor thread itself
acceptor.close();
}
Обратите внимание: вместо вызова acceptor.stop()
мы вызываем acceptor.afterTermination()
, чтобы напрямую закрыть сокет на стороне сервера.
Чтобы избежать ошибок, вызванных методом handle
в AcceptorThread
, мы также можем реализовать новый класс из исходного или просто попытаться перезаписать метод handle
, чтобы учесть, закрыт ли сокет на стороне сервера:
@Override
protected void handle() {
try {
if (ss.isClosed()) {
log.debug("The server-side socket is closed. No new connections will be allowed.");
return;
}
Socket s = ss.accept();
socketFactory.configureNewAcceptedSocket(s);
if (!queue.offer(new AcceptedSocket(s))) {
log.error("Denied enqueuing server-side socket {}", s);
s.close();
} else
log.debug("Enqueued server-side socket {}", s);
} catch (SocketTimeoutException e) { /* OK - just timed out */
log.trace("No connection established while waiting");
} catch (IOException e) {
log.error("Error while accepting connections", e);
}
}
Для тестирования можно попробовать примерно так:
public static void main(String[] args) throws Exception {
HapiContext ctx = new DefaultHapiContext();
HL7Service server = new MySimpleServer(8888);
server.startAndWait();
Connection client1 = ctx.newClient("127.0.0.1", 8888, false);
server.getRemoteConnections().forEach((connection) -> connection.close());
server.stopAndWait();
try {
Connection client2 = ctx.newClient("127.0.0.1", 8888, false);
} catch (Throwable t) {
t.printStackTrace();
}
ctx.close();
System.exit(0);
}