blob: 94d38d1492dd0ae9505200fb994ac35ac82e0dd1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.payara.tooling.server;
import org.netbeans.modules.payara.tooling.admin.ServerAdmin;
import org.netbeans.modules.payara.tooling.admin.ResultMap;
import org.netbeans.modules.payara.tooling.admin.CommandLocation;
import org.netbeans.modules.payara.tooling.admin.ResultString;
import org.netbeans.modules.payara.tooling.admin.CommandVersion;
import org.netbeans.modules.payara.tooling.TaskStateListener;
import org.netbeans.modules.payara.tooling.TaskState;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.text.MessageFormat;
import java.util.concurrent.*;
import java.util.logging.Level;
import org.netbeans.modules.payara.tooling.TaskEvent;
import org.netbeans.modules.payara.tooling.logging.Logger;
import org.netbeans.modules.payara.tooling.data.PayaraServer;
/**
* Check server status using administration commands <code>__locations</code>
* and <code>version</code> and also verify if server is at least listening
* on its administration port.
* <p/>
* Administration commands and port check are run in parallel to reduce delay.
* <p/>
* @author Tomas Kraus
*/
public class ServerStatus implements Closeable {
////////////////////////////////////////////////////////////////////////////
// Inner classes //
////////////////////////////////////////////////////////////////////////////
/**
* Individual server check status returned.
*/
public static enum Status {
/** Server status check passed. */
SUCCESS,
/** Server status check failed with <code>FAILED</code> result. */
FAILED,
/** Server status check failed on timeout. */
TIMEOUT,
/** Server status check failed on IO Exception. */
EXCEPTION,
/** Server status check failed because of invalid arguments. */
INVALID,
/** Server status check failed because of unexpected fatal issue. */
FATAL;
////////////////////////////////////////////////////////////////////////
// Methods //
////////////////////////////////////////////////////////////////////////
/**
* Convert <code>Status</code> value to <code>String</code>.
* <p/>
* @return A <code>String</code> representation of the value
* of this object.
*/
@Override
public String toString() {
switch(this) {
case SUCCESS: return "SUCCESS";
case FAILED: return "FAILED";
case TIMEOUT: return "TIMEOUT";
case EXCEPTION: return "EXCEPTION";
case INVALID: return "INVALID";
case FATAL: return "FATAL";
default:
throw new IllegalStateException("Unknown Status value");
}
}
}
/**
* Individual server status result including additional information.
*/
public static class Result {
////////////////////////////////////////////////////////////////////////
// Instance attributes //
////////////////////////////////////////////////////////////////////////
/** Individual server status returned. */
final Status status;
/** IO Exception caught. */
private final IOException ioe;
/** Fatal issue Exception caught. */
private final Exception ex;
/** Task failure event. */
private final TaskEvent failureEvent;
/** Server name. */
private final String serverName;
/** Exception message. */
private final String exceptionMeasage;
////////////////////////////////////////////////////////////////////////
// Constructors //
////////////////////////////////////////////////////////////////////////
/**
* Creates an instance of individual server status result.
* <p/>
* IO Exception caught in asynchronous task is stored.
* <p/>
* @param status Individual server status returned.
* @param ioe IO Exception caught in asynchronous task.
* @param failureEvent Failure cause.
* @param serverName Target Payara server name.
* @param exceptionMeasage Exception message from command task.
*/
Result(final Status status, final IOException ioe,
final TaskEvent failureEvent, final String serverName,
final String exceptionMeasage) {
this.status = status;
this.ioe = ioe;
this.ex = null;
this.failureEvent = failureEvent;
this.serverName = serverName;
this.exceptionMeasage = exceptionMeasage;
}
/**
* Creates an instance of individual server status result.
* <p/>
* Common Exception caught is stored.
* <p/>
* @param status Individual server status returned.
* @param ex Common Exception caught.
* @param failureEvent Failure cause.
* @param serverName Target Payara server name.
* @param exceptionMeasage Exception message from command task.
*/
Result(final Status status, final Exception ex,
final TaskEvent failureEvent, final String serverName,
final String exceptionMeasage) {
this.status = status;
this.ioe = null;
this.ex = ex;
this.failureEvent = failureEvent;
this.serverName = serverName;
this.exceptionMeasage = exceptionMeasage;
}
/**
* Creates an instance of individual server status result.
* <p/>
* No additional value except result is stored.
* <p/>
* @param status Individual server status returned.
* @param failureEvent Failure cause.
* @param serverName Target Payara server name.
* @param exceptionMeasage Exception message from command task.
*/
Result(final Status status, final TaskEvent failureEvent,
final String serverName, final String exceptionMeasage) {
this.status = status;
this.ioe = null;
this.ex = null;
this.failureEvent = failureEvent;
this.serverName = serverName;
this.exceptionMeasage = exceptionMeasage;
}
/**
* Creates an instance of individual server status result.
* <p/>
* IO Exception caught in asynchronous task is stored.
* <p/>
* @param status Individual server status returned.
* @param ioe IO Exception caught in asynchronous task.
*/
Result(final Status status, final IOException ioe) {
this(status, ioe, null, null, null);
}
/**
* Creates an instance of individual server status result.
* <p/>
* Common Exception caught is stored.
* <p/>
* @param status Individual server status returned.
* @param ex Common Exception caught.
*/
Result(final Status status, final Exception ex) {
this(status, ex, null, null, null);
}
/**
* Creates an instance of individual server status result.
* <p/>
* No additional value except result is stored.
* <p/>
* @param status Individual server status returned.
*/
Result(final Status status) {
this(status, null, null, null);
}
////////////////////////////////////////////////////////////////////////
// Getters //
////////////////////////////////////////////////////////////////////////
/**
* Get individual check task status.
* <p/>
* @return Individual check task status.
*/
public Status getStatus() {
return status;
}
/**
* Get task failure event.
* <p/>
* @return Task failure event.
*/
public TaskEvent getFailureEvent() {
return failureEvent;
}
/**
* Get server name.
* <p/>
* @return Server name.
*/
public String getServerName() {
return serverName;
}
/**
* Get exception message.
* <p/>
* @return Exception message.
*/
public String getExceptionMeasage() {
return exceptionMeasage;
}
}
/**
* Server status task execution result for <code>__locations</code> command
* including additional information.
* <p/>
* This class stores task execution result only. Value <code>SUCCESS</code>
* means that Locations command task execution finished successfully but it
* does not mean that administration command itself returned with
* <code>COMPLETED</code> status.
* When <code>SUCCESS</code> status is set, stored <code>result</code> value
* shall be examined too to see real administration command execution
* result.
*/
public static class ResultLocations extends Result {
////////////////////////////////////////////////////////////////////////
// Instance attributes //
////////////////////////////////////////////////////////////////////////
/** Command <code>__locations</code> execution result. */
final ResultMap<String, String> result;
////////////////////////////////////////////////////////////////////////
// Constructors //
////////////////////////////////////////////////////////////////////////
/**
* Creates an instance of individual server status result
* for <code>__locations</code> command.
* <p/>
* Command <code>__locations</code> result is stored.
* <p/>
* @param status Individual server status returned.
* @param failureEvent Failure cause.
* @param serverName Target Payara server name.
* @param exceptionMeasage Exception message from command task.
*/
ResultLocations(final ResultMap<String, String> result,
final Status status, final TaskEvent failureEvent,
final String serverName, final String exceptionMeasage) {
super(status, failureEvent, serverName, exceptionMeasage);
this.result = result;
}
/**
* Creates an instance of individual server status result
* for <code>__locations</code> command.
* <p/>
* Common Exception caught is stored.
* <p/>
* @param status Individual server status returned.
* @param ex Common Exception caught.
* @param failureEvent Failure cause.
* @param serverName Target Payara server name.
* @param exceptionMeasage Exception message from command task.
*/
ResultLocations(final Status status, final Exception ex,
final TaskEvent failureEvent, final String serverName,
final String exceptionMeasage) {
super(status, ex, failureEvent, serverName, exceptionMeasage);
this.result = null;
}
/**
* Creates an instance of individual server status result
* for <code>__locations</code> command.
* <p/>
* No additional value except result is stored.
* <p/>
* @param status Individual server status returned.
* @param failureEvent Failure cause.
* @param serverName Target Payara server name.
* @param exceptionMeasage Exception message from command task.
*/
ResultLocations(final Status status, final TaskEvent failureEvent,
final String serverName, final String exceptionMeasage) {
super(status, failureEvent, serverName, exceptionMeasage);
this.result = null;
}
////////////////////////////////////////////////////////////////////////
// Getters //
////////////////////////////////////////////////////////////////////////
/**
* Get <code>__locations</code> command execution result.
* <p/>
* @return <code>__locations</code> command execution result.
*/
public ResultMap<String, String> getResult() {
return result;
}
}
/**
* Individual server status result for <code>version</code> command
* including additional information.
* <p/>
* This class stores task execution result only. Value <code>SUCCESS</code>
* means that Locations command task execution finished successfully but it
* does not mean that administration command itself returned with
* <code>COMPLETED</code> status.
* When <code>SUCCESS</code> status is set, stored <code>result</code> value
* shall be examined too to see real administration command execution
* result.
*/
public static class ResultVersion extends Result {
////////////////////////////////////////////////////////////////////////
// Instance attributes //
////////////////////////////////////////////////////////////////////////
/** Command <code>version</code> execution result. */
final ResultString result;
////////////////////////////////////////////////////////////////////////
// Constructors //
////////////////////////////////////////////////////////////////////////
/**
* Creates an instance of individual server status result
* for <code>version</code> command.
* <p/>
* Command <code>version</code> result is stored.
* <p/>
* @param status Individual server status returned.
* @param failureEvent Failure cause.
* @param serverName Target Payara server name.
* @param exceptionMeasage Exception message from command task.
*/
ResultVersion(final ResultString result, final Status status,
final TaskEvent failureEvent, final String serverName,
final String exceptionMeasage) {
super(status, failureEvent, serverName, exceptionMeasage);
this.result = result;
}
/**
* Creates an instance of individual server status result
* for <code>version</code> command.
* <p/>
* Common Exception caught is stored.
* <p/>
* @param status Individual server status returned.
* @param ex Common Exception caught.
* @param failureEvent Failure cause.
* @param serverName Target Payara server name.
* @param exceptionMeasage Exception message from command task.
*/
ResultVersion(final Status status, final Exception ex,
final TaskEvent failureEvent, final String serverName,
final String exceptionMeasage) {
super(status, ex, failureEvent, serverName, exceptionMeasage);
this.result = null;
}
/**
* Creates an instance of individual server status result
* for <code>version</code> command.
* <p/>
* No additional value except result is stored.
* <p/>
* @param status Individual server status returned.
* @param failureEvent Failure cause.
* @param serverName Target Payara server name.
* @param exceptionMeasage Exception message from command task.
*/
ResultVersion(final Status status, final TaskEvent failureEvent,
final String serverName, final String exceptionMeasage) {
super(status, failureEvent, serverName, exceptionMeasage);
this.result = null;
}
////////////////////////////////////////////////////////////////////////
// Getters //
////////////////////////////////////////////////////////////////////////
/**
* Get <code>version</code> command execution result.
* <p/>
* @return <code>version</code> command execution result.
*/
public ResultString getResult() {
return result;
}
}
/**
* Common individual server status check task.
*/
private static abstract class Task implements TaskStateListener {
////////////////////////////////////////////////////////////////////////
// Static methods //
////////////////////////////////////////////////////////////////////////
/**
* Format time value in miliseconds to be printed as value in seconds
* and miliseconds <code>s.ms<code>.
* <p/>
* @param tm Time value in miliseconds
* @return Time string formated as econds and miliseconds
* <code>s.ms<code>.
*/
static String tm(final long tm) {
StringBuilder sb = new StringBuilder(8);
sb.append(Long.toString(tm/1000));
sb.append('.');
sb.append(Long.toString(tm%1000));
return sb.toString();
}
////////////////////////////////////////////////////////////////////////
// Instance attributes //
////////////////////////////////////////////////////////////////////////
/** Payara server to be tested. */
final PayaraServer server;
/** Task start time. Used for logging purposes. Value of <code>-1</code>
* means that start time was not set.*/
long tmStart;
/** Task failure event filled by last state change. */
TaskEvent failureEvent;
/** Server name filled by last state change. */
String serverName;
/** Exception message filled by last state change. */
String exceptionMeasage;
////////////////////////////////////////////////////////////////////////
// Constructors //
////////////////////////////////////////////////////////////////////////
/**
* Creates an instance of common individual server status check.
* <p/>
* @param server Payara server to be checked.
*/
Task(final PayaraServer server) {
this.server = server;
this.tmStart = -1;
}
////////////////////////////////////////////////////////////////////////
// Getters and setters //
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// Methods //
////////////////////////////////////////////////////////////////////////
/**
* Compute task result waiting timeout based on task start time, actual
* time and minimal timeout limit.
* <p/>
* @param startup Startup mode to select longer timeout.
* @return Task result waiting timeout.
*/
long timeout(final boolean startup) {
long timeout = (startup ? COMAND_STARTUP_TIMEOUT : COMAND_TIMEOUT)
- System.currentTimeMillis() + tmStart;
if (timeout > COMAND_TIMEOUT_MIN) {
return timeout;
} else {
return COMAND_TIMEOUT_MIN;
}
}
/**
* Store event that caused task failure.
* <p/>
* @param newState Current task state.
* @param event Event that caused task change.
* @param args Unused interface parameter.
*/
@Override
public void operationStateChanged(
final TaskState newState, final TaskEvent event,
final String[] args) {
if (args != null && args.length >= 3) {
serverName = args[0];
exceptionMeasage = args[2];
} else {
serverName = exceptionMeasage = null;
}
switch(newState) {
case FAILED:
failureEvent = event;
}
}
}
/**
* Individual server status check task to verify if server administration
* port is alive.
* <p/>
* This task does not run in a separate thread but uses existing main thread
* instead.
*/
private static class AdminPortTask extends Task {
////////////////////////////////////////////////////////////////////////
// Class attributes //
////////////////////////////////////////////////////////////////////////
/** Logger instance for this class. */
private static final Logger LOGGER = new Logger(AdminPortTask.class);
////////////////////////////////////////////////////////////////////////
// Instance attributes //
////////////////////////////////////////////////////////////////////////
/** Server administration interface host. */
String host;
/** Server administration interface port. */
int port;
/** Socked connecting timeout [ms]. */
int timeout;
/** Server administration port status check result. */
private Result result;
////////////////////////////////////////////////////////////////////////
// Constructors //
////////////////////////////////////////////////////////////////////////
/**
* Creates an instance of administration port status check.
* <p/>
* @param server Payara server to be checked.
* @param timeout Socked connecting timeout.
*/
AdminPortTask(final PayaraServer server, final int timeout) {
super(server);
this.host = server.getHost();
this.port = server.getAdminPort();
this.timeout = timeout;
}
////////////////////////////////////////////////////////////////////////
// Getters //
////////////////////////////////////////////////////////////////////////
/**
* Get server administration port status check result.
* <p/>
* @return Server administration port status check result.
*/
Result getResult() {
return result;
}
////////////////////////////////////////////////////////////////////////
// Methods //
////////////////////////////////////////////////////////////////////////
/**
* Close socket and handle <code>IOException</code> that could
* be thrown.
* <p/>
* @param socket Socket to be closed.
*/
private void closeSocket(final Socket socket) {
try {
socket.close();
} catch (IOException ioe) {
handleIOException(ioe, host, port,
"Socket closing failed when connecting to {0}:{1}: {2}");
}
}
/**
* Handle IO Exception caught in server administration port verification
* task.
* <p/>
* @param ioe <code>IOException</code> caught.
* @param host Server administration host.
* @param port Server administration port.
* @param message Message to be logged. Shall not be <code>null</code>.
*/
private void handleIOException(final IOException ioe,
final String host, final int port, final String message) {
final String METHOD = "handleIOException";
String logMsg = MessageFormat.format(message, new Object[] {
server.getName(), host, Integer.toString(port),
ioe.getMessage()});
if (tmStart >= 0 && LOGGER.isLoggable(Level.FINE)) {
long tm = System.currentTimeMillis() - tmStart;
LOGGER.log(Level.FINE, METHOD, "messageTm",
new Object[] {logMsg, tm(tm)});
} else {
LOGGER.log(Level.INFO, METHOD, "message", logMsg);
}
}
// Based on original code from
// org.netbeans.modules.payara.common.CommonServerSupport.isRunning(...)
/**
* Parent thread task to verify if server administration port is alive.
* <p/>
* @return Returns <code>true</code> when server administration port
* is alive or <code>false</code> otherwise.
*/
Result check() {
final String METHOD = "check";
if (port < 0 || host == null) {
result = new Result(Status.INVALID);
return result;
}
this.tmStart = System.currentTimeMillis();
InetSocketAddress sa = new InetSocketAddress(host, port);
Socket socket = new Socket();
try {
socket.connect(sa, timeout);
socket.setSoTimeout(timeout);
} catch (java.net.ConnectException ce) {
handleIOException(ce, host, port,
"[{0}] Port check could not connect to {1}:{2}: {3}");
result = new Result(Status.FAILED, ce);
return result;
} catch (java.net.SocketTimeoutException ste) {
handleIOException(ste, host, port,
"[{0}] Port check timeout when connecting to {1}:{2}: {3}");
result = new Result(Status.TIMEOUT, ste);
return result;
} catch (IOException ioe) {
handleIOException(ioe, host, port,
"[{0}] Port check caught IO exception when connecting to {1}:{2}: {3}");
result = new Result(Status.EXCEPTION, ioe);
return result;
} finally {
closeSocket(socket);
}
if (tmStart >= 0 && LOGGER.isLoggable(Level.FINE)) {
long tm = System.currentTimeMillis() - tmStart;
LOGGER.log(Level.FINE, METHOD, "success",
new Object[] {tm(tm), server.getName()});
}
result = new Result(Status.SUCCESS);
return result;
}
}
/**
* Individual server status check task with <code>__locations</code>
* administration command execution.
*/
private static class LocationsTask extends Task {
////////////////////////////////////////////////////////////////////////
// Class attributes //
////////////////////////////////////////////////////////////////////////
/** Logger instance for this class. */
private static final Logger LOGGER = new Logger(LocationsTask.class);
////////////////////////////////////////////////////////////////////////
// Instance attributes //
////////////////////////////////////////////////////////////////////////
/** Locations command. */
private final CommandLocation command;
/** Locations command execution result; */
private Future<ResultMap<String, String>> future;
/** Locations command result; */
ResultMap<String, String> taskResult;
/** Locations command status check result. */
private ResultLocations result;
/** Startup mode. Triggers longer administration commands execution
* timeouts when <code>true</code>. */
private final boolean startup;
////////////////////////////////////////////////////////////////////////
// Constructors //
////////////////////////////////////////////////////////////////////////
/**
* Creates an instance of <code>__locations</code> server status check.
* <p/>
* @param server Payara server to be checked.
* @param startup Trigger startup mode. Triggers longer administration
* commands execution timeouts when <code>true</code>.
*/
LocationsTask(final PayaraServer server, final boolean startup) {
super(server);
this.command = new CommandLocation();
this.startup = startup;
}
////////////////////////////////////////////////////////////////////////
// Getters //
////////////////////////////////////////////////////////////////////////
/**
* Get <code>__locations</code> command status check result.
* <p/>
* @return <code>__locations</code> command status check result.
*/
ResultLocations getResult() {
return result;
}
////////////////////////////////////////////////////////////////////////
// Methods //
////////////////////////////////////////////////////////////////////////
/**
* Start server Location task.
*/
void start(final ExecutorService executor) {
final String METHOD = "start";
this.tmStart = System.currentTimeMillis();
future = ServerAdmin.<ResultMap<String, String>>
exec(executor, server, command, this);
if (tmStart >=0 && LOGGER.isLoggable(Level.FINE)) {
long tm = System.currentTimeMillis() - tmStart;
LOGGER.log(Level.FINE, METHOD, "started", tm(tm));
}
}
/**
* Log Exception caught on task join.
* <p/>
* @param ex Exception caught.
*/
private void logExceptionOnJoin(final Exception ex) {
final String METHOD = "logExceptionOnJoin";
LOGGER.log(Level.FINE, METHOD, "failed",
new Object[] {tm(System.currentTimeMillis() - tmStart),
ex.getClass().getName(),
ex.getMessage() != null ? ex.getMessage() : ""});
}
/**
* Wait for server Location task to finish.
*/
void join() {
final String METHOD = "join";
try {
taskResult = future.get(
timeout(startup), TimeUnit.MILLISECONDS);
result = new ResultLocations(taskResult, Status.SUCCESS,
failureEvent, serverName, exceptionMeasage);
LOGGER.log(Level.FINE, METHOD, "completed",
tm(System.currentTimeMillis() - tmStart));
// This means administration port is not responding.
} catch (TimeoutException te) {
result = new ResultLocations(Status.TIMEOUT,
failureEvent, serverName, exceptionMeasage);
logExceptionOnJoin(te);
// Expected exceptions are handled in call() method so this
// is something serious.
} catch (ExecutionException ee) {
result = new ResultLocations(Status.FATAL, ee,
failureEvent, serverName, exceptionMeasage);
logExceptionOnJoin(ee);
// Interrupted after administration port check failed.
} catch (InterruptedException | CancellationException ie) {
result = new ResultLocations(Status.FAILED, ie,
failureEvent, serverName, exceptionMeasage);
logExceptionOnJoin(ie);
// Cancelled after administration port check failed.
}
}
/**
* Attempt to cancel execution of this task.
*/
void cancel() {
if (!future.isDone()) {
future.cancel(true);
}
}
}
/**
* Individual server status check task with <code>version</code>
* administration command execution.
*/
private static class VersionTask extends Task {
////////////////////////////////////////////////////////////////////////
// Class attributes //
////////////////////////////////////////////////////////////////////////
/** Logger instance for this class. */
private static final Logger LOGGER = new Logger(VersionTask.class);
////////////////////////////////////////////////////////////////////////
// Instance attributes //
////////////////////////////////////////////////////////////////////////
/** Version command. */
private final CommandVersion command;
/** Version command execution result; */
private Future<ResultString> future;
/** Version command result; */
ResultString taskResult;
/** Version command status check result. */
private ResultVersion result;
/** Startup mode. Triggers longer administration commands execution
* timeouts when <code>true</code>. */
private final boolean startup;
////////////////////////////////////////////////////////////////////////
// Constructors //
////////////////////////////////////////////////////////////////////////
/**
* Creates an instance of <code>version</code> server status check.
* <p/>
* @param server Payara server to be checked.
* @param startup Trigger startup mode. Triggers longer administration
* commands execution timeouts when <code>true</code>.
*/
VersionTask(final PayaraServer server, final boolean startup) {
super(server);
this.command = new CommandVersion();
this.startup = startup;
}
////////////////////////////////////////////////////////////////////////
// Getters //
////////////////////////////////////////////////////////////////////////
/**
* Get <code>version</code> command status check result.
* <p/>
* @return <code>version</code> command status check result.
*/
ResultVersion getResult() {
return result;
}
////////////////////////////////////////////////////////////////////////
// Methods //
////////////////////////////////////////////////////////////////////////
/**
* Start server Version task.
*/
void start(final ExecutorService executor) {
final String METHOD = "start";
this.tmStart = System.currentTimeMillis();
future = ServerAdmin.<ResultString>
exec(executor, server, command, this);
if (tmStart >=0 && LOGGER.isLoggable(Level.FINE)) {
long tm = System.currentTimeMillis() - tmStart;
LOGGER.log(Level.FINE, METHOD, "started", tm(tm));
}
}
/**
* Log Exception caught on task join.
* <p/>
* @param ex Exception caught.
*/
private void logExceptionOnJoin(final Exception ex) {
final String METHOD = "logExceptionOnJoin";
LOGGER.log(Level.FINE, METHOD, "failed",
new Object[] {tm(System.currentTimeMillis() - tmStart),
ex.getClass().getName(),
ex.getMessage() != null ? ex.getMessage() : ""});
}
/**
* Wait for server Version task to finish.
*/
void join() {
final String METHOD = "join";
try {
taskResult = future.get(
timeout(startup), TimeUnit.MILLISECONDS);
result = new ResultVersion(taskResult, Status.SUCCESS,
failureEvent, serverName, exceptionMeasage);
LOGGER.log(Level.FINE, "completed",
tm(System.currentTimeMillis() - tmStart));
// This means administration port is not responding.
} catch (TimeoutException te) {
result = new ResultVersion(Status.TIMEOUT,
failureEvent, serverName, exceptionMeasage);
logExceptionOnJoin(te);
// Expected exceptions are handled in call() method so this
// is something serious.
} catch (ExecutionException ee) {
result = new ResultVersion(Status.FATAL, ee,
failureEvent, serverName, exceptionMeasage);
logExceptionOnJoin(ee);
// Interrupted after administration port check failed.
} catch (InterruptedException | CancellationException ie) {
result = new ResultVersion(Status.FAILED, ie,
failureEvent, serverName, exceptionMeasage);
logExceptionOnJoin(ie);
// Cancelled after administration port check failed.
}
}
/**
* Attempt to cancel execution of this task.
*/
void cancel() {
if (!future.isDone()) {
future.cancel(true);
}
}
}
////////////////////////////////////////////////////////////////////////////
// Class attributes //
////////////////////////////////////////////////////////////////////////////
/** Logger instance for this class. */
private static final Logger LOGGER = new Logger(ServerStatus.class);
/** Executor thread pool size (amount of threads to run in parallel). */
private static final int EXECUTOR_POOL_SIZE = 2;
/** Administration port connect timeout [ms]. */
private static final int CONNECT_TIMEOUT = 15000;
/** Minimal administration command execution timeout [ms]. */
private static final int COMAND_TIMEOUT_MIN = 100;
/** Administration command execution timeout [ms]. */
private static final int COMAND_TIMEOUT = 30000;
/** Administration command execution timeout [ms] in startup mode. */
private static final int COMAND_STARTUP_TIMEOUT = 600000;
////////////////////////////////////////////////////////////////////////////
// Instance attributes //
////////////////////////////////////////////////////////////////////////////
/** Executor used to run asynchronous server status checks in parallel. */
private final ExecutorService executor;
/** Server status check task to verify if server administration
* port is alive. */
private final AdminPortTask adminPortTask;
/** Server status check task with <code>version</code> administration
* command. */
private final VersionTask versionTask;
/** Server status check task with <code>__locations</code> administration
* command. */
private final LocationsTask locationsTask;
/** Asynchronous server status checks start time. Used for logging
* purposes. Value of <code>-1</code> means that start time was not set. */
////////////////////////////////////////////////////////////////////////////
// Constructors //
////////////////////////////////////////////////////////////////////////////
/**
* Creates an instance of server status check.
* <p/>
* Method {@link #close()} must be called at the end to release
* system resources.
* <p/>
* @param server Payara server to be checked.
* @param startup Trigger startup mode. Triggers longer administration
* commands execution timeouts when <code>true</code>.
*/
public ServerStatus(final PayaraServer server, final boolean startup) {
this.executor = ServerAdmin.executor(EXECUTOR_POOL_SIZE);
this.adminPortTask = new AdminPortTask(server, CONNECT_TIMEOUT);
this.versionTask = new VersionTask(server, startup);
this.locationsTask = new LocationsTask(server, startup);
}
////////////////////////////////////////////////////////////////////////////
// Getters //
////////////////////////////////////////////////////////////////////////////
/**
* Get server administration port status check result.
* <p/>
* @return Server administration port status check result.
*/
public Result getAdminPortResult() {
return adminPortTask.result;
}
/**
* Get <code>version</code> command status check result.
* <p/>
* @return <code>version</code> command status check result.
*/
public ResultVersion getVersionResult() {
return versionTask.result;
}
/**
* Get <code>__locations</code> command status check result.
* <p/>
* @return <code>__locations</code> command status check result.
*/
public ResultLocations getLocationsResult() {
return locationsTask.result;
}
////////////////////////////////////////////////////////////////////////////
// Methods //
////////////////////////////////////////////////////////////////////////////
/**
* Run asynchronous server status checks.
* <p/>
* Server administration port status check is run in parent thread. When
* administration port has not been available, remaining command tasks
* are canceled.
*/
public void check() {
versionTask.start(executor);
locationsTask.start(executor);
Result result = adminPortTask.check();
if (result.status != Status.SUCCESS) {
versionTask.cancel();
locationsTask.cancel();
}
versionTask.join();
locationsTask.join();
}
/**
* Clean up all resources.
* <p/>
* Removes internal thread pool.
*
*/
@Override
public void close() {
executor.shutdownNow();
}
}