Commit e522a11f authored by Stephan Wahlbrink's avatar Stephan Wahlbrink
Browse files

Bug 576774: [RJ-Servi] Migrate to java.time API

Also:
  - Rename some config properties to more meaningful names
  - Fix display names of properties in MXBeans

Change-Id: I120cc837e51e321f01ca06122c103ce2d3d96b37
parent cf8326c0
......@@ -3,6 +3,8 @@
## RJ 4.5.0 ~ StatET 4.5.0
### Services
* The data access for tool command handler is enhanced. Implementations of handlers need to be
adapted.
......@@ -13,6 +15,15 @@
(Bug 574779)
### RServi Node and Pool
* The configuration and pool API is migrated to make use of `java.time`. Timestamps are
represented by `Instant` and durations like timeouts by `Duration`, except in MXBeans.
In the config classes also some related properties are renamed to more meaningful names.
For property accessors, which still use long for timestamps and durations, the postfix `Millis`
is added to their names.
Applications need to be adapted. (Bug 576774)
## RJ 4.4.0 ~ StatET 4.4.0
......
......@@ -14,8 +14,6 @@
package org.eclipse.statet.rj.servi.pool;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
......@@ -28,6 +26,7 @@ import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullLateInit;
import static org.eclipse.statet.internal.rj.servi.APool2.CLIENT_ALLOCATION_RENEW_PERIOD_MILLIS_PROPERTY_KEY;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
......@@ -36,6 +35,7 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javax.security.auth.login.LoginException;
......@@ -70,9 +70,9 @@ import org.eclipse.statet.rj.servi.test.Accessor;
public class JMPoolTest extends AbstractServiTest {
private static int NODE_STARTUP_MILLIS= 7_000;
private static Duration NODE_STARTUP_DURATION= Duration.ofSeconds(7);
private static int WAIT_IDLE_MILLIS= 30_000;
private static Duration WAIT_IDLE_DURATION= Duration.ofSeconds(30);
private static double TIME_TOLERANCE_MILLIS= 10;
......@@ -230,7 +230,7 @@ public class JMPoolTest extends AbstractServiTest {
}
@Test
public void TotalNodes_borrowMax() throws Exception,
public void TotalNodes_allocateMax() throws Exception,
InterruptedException {
final PoolConfig poolConfig= new PoolConfig();
poolConfig.setMaxTotalCount(2);
......@@ -243,7 +243,7 @@ public class JMPoolTest extends AbstractServiTest {
assertNodeOperative(servi1);
assertNodeOperative(servi2);
Thread.sleep(WAIT_IDLE_MILLIS);
Thread.sleep(WAIT_IDLE_DURATION.toMillis());
assertIdleCount(0);
closeServi(servi1);
......@@ -251,11 +251,12 @@ public class JMPoolTest extends AbstractServiTest {
}
@Test
public void TotalNodes_borrowTimeout() throws Exception {
public void TotalNodes_allocateTimeout() throws Exception {
final PoolConfig poolConfig= new PoolConfig();
poolConfig.setMaxTotalCount(2);
this.server.setPoolConfig(poolConfig);
this.server.start();
final var timeout= nonNullAssert(poolConfig.getAllocationTimeout());
final RServi servi1= getServi("test1");
assertNotNull(servi1);
......@@ -263,10 +264,10 @@ public class JMPoolTest extends AbstractServiTest {
final long t2= System.nanoTime();
final RServi servi2= getServi("test2");
assertNotNull(servi2);
{ final long d2= TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t2);
final long dMax= poolConfig.getMaxWaitTime() + NODE_STARTUP_MILLIS;
assertTrue(d2 < dMax,
() -> String.format("duration expected: < %1$sms, actual: %2$sms", dMax, d2) );
{ final Duration d2= Duration.ofNanos(System.nanoTime() - t2);
final Duration dMax= timeout.plus(NODE_STARTUP_DURATION);
assertTrue(d2.compareTo(dMax) < 0, () ->
String.format("duration expected: < %1$sms, actual: %2$sms", dMax, d2) );
}
final long t3= System.nanoTime();
......@@ -276,16 +277,17 @@ public class JMPoolTest extends AbstractServiTest {
throw new AssertionError("totalCount");
}
catch (final NoSuchElementException e) {
final long d3= TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t3);
final long dExpected= poolConfig.getMaxWaitTime();
final long dTol= 500;
assertTrue(d3 > poolConfig.getMaxWaitTime() - dTol && d3 < poolConfig.getMaxWaitTime() + dTol,
() -> String.format("duration expected: %1$sms (±%3$sms), actual: %2$sms", dExpected, d3, dTol));
final Duration d3= Duration.ofNanos(System.nanoTime() - t3);
final Duration dExpected= timeout;
final double deltaMillis= 500;
assertDurationEquals(dExpected, d3, deltaMillis, () ->
String.format("duration expected: %1$sms (±%3$sms), actual: %2$sms",
dExpected, d3, deltaMillis ));
}
}
@Test
public void UsageCount_borrowMax() throws Exception {
public void UsageCount_allocateMax() throws Exception {
final ProgressMonitor m1= new NullProgressMonitor();
final ProgressMonitor m2= new NullProgressMonitor();
......@@ -327,7 +329,7 @@ public class JMPoolTest extends AbstractServiTest {
final PoolNodeObject node1= assertSinglePoolNode();
awaitStateCondition(node1, (state) -> (state != PoolNodeState.ALLOCATED),
(int)(1.2 * periodMillis) + WAIT_IDLE_MILLIS );
Duration.ofMillis((long)(1.2 * periodMillis)).plus(WAIT_IDLE_DURATION) );
skipChecking(node1);
assertEquals(PoolNodeState.ALLOCATED, node1.getState());
assertNodeOperative(servi1);
......@@ -359,7 +361,7 @@ public class JMPoolTest extends AbstractServiTest {
clientCheckJob.cancel(false);
awaitStateCondition(node1, (state) -> (state != PoolNodeState.ALLOCATED),
(int)(1.2 * periodMillis) + WAIT_IDLE_MILLIS );
Duration.ofMillis((long)(1.2 * periodMillis)).plus(WAIT_IDLE_DURATION) );
skipChecking(node1);
assertDisposingToDisposed(node1);
......@@ -463,7 +465,7 @@ public class JMPoolTest extends AbstractServiTest {
skipChecking(node1);
assertEquals(PoolNodeState.IDLING, node1.getState());
node1.evict(0);
node1.evict(null);
assertDisposingToDisposed(node1);
}
......@@ -514,22 +516,31 @@ public class JMPoolTest extends AbstractServiTest {
this.server.setPoolConfig(poolConfig);
this.server.start();
Duration actual;
assertIdleCount(1);
final PoolNodeObject node1= assertSinglePoolNode();
assertEquals(-1, node1.getLastestAllocationDuration(), "duration");
actual= node1.getLastestAllocationDuration();
assertNull(actual, "duration");
final long startNanos= System.nanoTime();
final RServi servi1= getServi("test1");
assertEquals(NANOSECONDS.toMillis(System.nanoTime() - startNanos), node1.getLastestAllocationDuration(),
actual= node1.getLastestAllocationDuration();
assertNotNull(actual);
assertDurationEquals(Duration.ofNanos(System.nanoTime() - startNanos), actual,
TIME_TOLERANCE_MILLIS, "duration" );
Thread.sleep(3000);
assertEquals(NANOSECONDS.toMillis(System.nanoTime() - startNanos), node1.getLastestAllocationDuration(),
actual= node1.getLastestAllocationDuration();
assertNotNull(actual);
assertDurationEquals(Duration.ofNanos(System.nanoTime() - startNanos), actual,
TIME_TOLERANCE_MILLIS, "duration" );
final long endNanos= System.nanoTime();
closeServi(servi1);
assertEquals(NANOSECONDS.toMillis(endNanos - startNanos), node1.getLastestAllocationDuration(),
actual= node1.getLastestAllocationDuration();
assertNotNull(actual);
assertDurationEquals(Duration.ofNanos(endNanos - startNanos), actual,
TIME_TOLERANCE_MILLIS, "duration" );
}
......@@ -546,7 +557,7 @@ public class JMPoolTest extends AbstractServiTest {
final PoolNodeObject node1= assertSinglePoolNode();
closeServi(servi1);
node1.evict(0);
node1.evict(null);
skipChecking(node1);
assertDisposingToDisposed(node1);
......@@ -564,7 +575,7 @@ public class JMPoolTest extends AbstractServiTest {
final PoolNodeObject node1= assertSinglePoolNode();
assertEquals(PoolNodeState.ALLOCATED, node1.getState());
node1.evict(0);
node1.evict(null);
skipChecking(node1);
assertDisposingToDisposed(node1);
......@@ -602,7 +613,7 @@ public class JMPoolTest extends AbstractServiTest {
}
final PoolNodeObject node1= assertSinglePoolNode();
assertEquals(PoolNodeState.ALLOCATED, node1.getState());
node1.evict(0);
node1.evict(null);
skipChecking(node1);
assertDisposingToDisposed(node1);
......@@ -626,7 +637,7 @@ public class JMPoolTest extends AbstractServiTest {
final Process process= nonNullAssert((Process)nodeHandler.getFieldObj("process"));
process.destroy();
node1.evict(0);
node1.evict(null);
skipChecking(node1);
assertDisposingToDisposed(node1);
......@@ -663,7 +674,7 @@ public class JMPoolTest extends AbstractServiTest {
if (expected == poolStatus.getNumIdling()) {
return;
}
if (TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t) > WAIT_IDLE_MILLIS) {
if (System.nanoTime() - t > WAIT_IDLE_DURATION.toNanos()) {
assertEquals(expected, poolStatus.getNumIdling(), "num idle");
}
Thread.sleep(100);
......@@ -671,17 +682,17 @@ public class JMPoolTest extends AbstractServiTest {
}
private void skipChecking(final PoolNodeObject node) throws InterruptedException {
awaitStateCondition(node, (state) -> (state != PoolNodeState.CHECKING), WAIT_IDLE_MILLIS);
awaitStateCondition(node, (state) -> (state != PoolNodeState.CHECKING), WAIT_IDLE_DURATION);
}
private void awaitStateCondition(final PoolNodeObject node,
final Predicate<PoolNodeState> condition, final int timeoutMillis) throws InterruptedException {
final Predicate<PoolNodeState> condition, final Duration timeout) throws InterruptedException {
final long t= System.nanoTime();
while (true) {
if (condition.test(node.getState())) {
return;
}
if (TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t) > timeoutMillis) {
if (System.nanoTime() - t > timeout.toNanos()) {
return;
}
Thread.sleep(100);
......@@ -696,9 +707,19 @@ public class JMPoolTest extends AbstractServiTest {
assertEquals(PoolNodeState.DISPOSING, state, "state");
}
awaitStateCondition(node, (state) -> (state != PoolNodeState.DISPOSING), WAIT_IDLE_MILLIS);
awaitStateCondition(node, (state) -> (state != PoolNodeState.DISPOSING), WAIT_IDLE_DURATION);
assertEquals(PoolNodeState.DISPOSED, node.getState(), "state");
}
private void assertDurationEquals(final Duration expected, final Duration actual,
final double deltaMillis, final String message) {
assertEquals(expected.toMillis(), actual.toMillis(), deltaMillis, message);
}
private void assertDurationEquals(final Duration expected, final Duration actual,
final double deltaMillis, final Supplier<String> messageSupplier) {
assertEquals(expected.toMillis(), actual.toMillis(), deltaMillis, messageSupplier);
}
}
......@@ -20,8 +20,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;
import javax.management.OperationsException;
import javax.security.auth.login.LoginException;
......@@ -191,9 +191,9 @@ public class LocalNodeTest extends AbstractLocalNodeTest {
final long t1= System.nanoTime();
this.localR.stop();
final long d1= TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t1);
final long dMax= new RServiNodeConfig().getStartStopTimeout() + 1500;
assertTrue(d1 < new RServiNodeConfig().getStartStopTimeout() + 1500,
final Duration d1= Duration.ofNanos(System.nanoTime() - t1);
final Duration dMax= new RServiNodeConfig().getStartStopTimeout().plusMillis(1500);
assertTrue(d1.compareTo(dMax) < 0,
() -> String.format("duration expected: < %1$sms, actual: %2$sms", dMax, d1) );
}
......
......@@ -14,6 +14,10 @@
package org.eclipse.statet.rj.servi.webapp;
import java.time.Instant;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.rmi.RMIAddress;
import org.eclipse.statet.rj.RjException;
......@@ -23,21 +27,22 @@ import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
import org.eclipse.statet.rj.servi.pool.PoolServer;
@NonNullByDefault
public class PoolItemBean extends PoolNodeItem {
public PoolItemBean(final PoolNodeObject poolObj, final long stamp) {
public PoolItemBean(final PoolNodeObject poolObj, final Instant stamp) {
super(poolObj, stamp);
}
public String getRMIAddress() {
public @Nullable String getRMIAddress() {
final RMIAddress address= getAddress();
return (address != null) ? address.getAddress() : null;
}
public String actionEnableConsole() {
public @Nullable String actionEnableConsole() {
try {
super.enableConsole("none");
}
......@@ -47,7 +52,7 @@ public class PoolItemBean extends PoolNodeItem {
return null;
}
public String actionDisableConsole() {
public @Nullable String actionDisableConsole() {
try {
super.disableConsole();
}
......@@ -67,7 +72,7 @@ public class PoolItemBean extends PoolNodeItem {
}
public void actionKill() {
evict(0);
evict(null);
}
}
......@@ -14,14 +14,20 @@
package org.eclipse.statet.rj.servi.webapp;
import java.time.Instant;
import javax.annotation.PostConstruct;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
import org.eclipse.statet.rj.servi.pool.PoolStatus;
import org.eclipse.statet.rj.servi.pool.RServiPoolManager;
@NonNullByDefault
public class PoolStatusBean extends PoolStatus<PoolItemBean> {
......@@ -40,7 +46,7 @@ public class PoolStatusBean extends PoolStatus<PoolItemBean> {
}
private void load() {
final long stamp= System.currentTimeMillis();
final Instant stamp= Instant.now();
final RServiPoolManager poolManager= this.server.getManager();
if (poolManager == null) {
FacesUtils.addErrorMessage(null, "The pool is currently not available.");
......@@ -49,7 +55,7 @@ public class PoolStatusBean extends PoolStatus<PoolItemBean> {
}
@Override
protected PoolNodeItem createPoolItem(final PoolNodeObject itemData, final long stamp) {
protected PoolNodeItem createPoolItem(final PoolNodeObject itemData, final Instant stamp) {
return new PoolItemBean(itemData, stamp);
}
......@@ -59,7 +65,7 @@ public class PoolStatusBean extends PoolStatus<PoolItemBean> {
}
public synchronized long getStamp() {
public synchronized Instant getStamp() {
check();
return super.getStatusStamp();
}
......@@ -76,16 +82,16 @@ public class PoolStatusBean extends PoolStatus<PoolItemBean> {
}
public String actionRefresh() {
public @Nullable String actionRefresh() {
return null;
}
public synchronized String actionEnableAutoRefresh() {
public synchronized @Nullable String actionEnableAutoRefresh() {
this.autoRefresh= true;
return null;
}
public synchronized String actionDisableAutoRefresh() {
public synchronized @Nullable String actionDisableAutoRefresh() {
this.autoRefresh= false;
return null;
}
......
......@@ -425,15 +425,12 @@ public class LocalNodeFactory implements NodeFactory {
p.rStartupSnippet= config.getRStartupSnippet();
long timeout= config.getStartStopTimeout();
if (timeout > 0) {
timeout= TimeUnit.MILLISECONDS.toNanos(timeout);
}
final var timeout= config.getStartStopTimeout();
synchronized (this) {
this.verbose= config.getEnableVerbose();
this.baseConfig= config;
this.processConfig= p;
this.timeoutNanos= timeout;
this.timeoutNanos= (timeout != null) ? timeout.toNanos() : -1;
}
}
......
......@@ -19,6 +19,7 @@ import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullLateInit;
import java.nio.file.Path;
import java.rmi.RemoteException;
import java.time.Instant;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
......@@ -47,11 +48,10 @@ public abstract class NodeHandler {
boolean isConsoleEnabled;
private long shutdownTime;
private @Nullable Instant shutdownTime;
public NodeHandler() {
this.shutdownTime= -1;
}
......@@ -111,7 +111,7 @@ public abstract class NodeHandler {
}
void shutdown() throws RemoteException {
this.shutdownTime= System.currentTimeMillis();
this.shutdownTime= Instant.now();
this.clientHandler= null;
setClientLabel(null);
final RServiNode node= this.node;
......@@ -137,7 +137,10 @@ public abstract class NodeHandler {
return this.clientLabel;
}
public long getShutdownTime() {
/**
* @since 4.5
*/
public @Nullable Instant getShutdownTime() {
return this.shutdownTime;
}
......
......@@ -16,6 +16,7 @@ package org.eclipse.statet.internal.rj.servi;
import static org.eclipse.statet.jcommons.lang.SystemUtils.OS_WIN;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
......@@ -191,6 +192,74 @@ public class Utils {
}
public static boolean isNegative(final @Nullable Duration duration) {
return (duration != null && duration.isNegative());
}
private static boolean isSign(final char c) {
return (c == '+' || c == '-');
}
private static boolean isDigit(final char c) {
return (c >= '0' && c <= '9');
}
public static Duration parseDuration(final String s) {
if (!s.isEmpty()
&& (isSign(s.charAt(0)) ?
s.length() >= 2 && isDigit(s.charAt(1)) :
isDigit(s.charAt(0)) )) {
final long millis= Long.parseLong(s);
return Duration.ofMillis(millis);
}
return Duration.parse(s);
}
public static Duration parseDuration(final @Nullable String s,
final Duration defaultValue) {
if (s == null) {
return defaultValue;
}
return parseDuration(s);
}
public static String serDuration(final Duration duration) {
return Long.toString(duration.toMillis());
}
public static @Nullable Duration parseNullableDuration(final String s) {
if (s.isEmpty()) {
return null;
}
if ((isSign(s.charAt(0)) ?
s.length() >= 2 && isDigit(s.charAt(1)) :
isDigit(s.charAt(0)) )) {
final long millis= Long.parseLong(s);
if (millis == -1) {
return null;
}
return Duration.ofMillis(millis);
}
return Duration.parse(s);
}
public static @Nullable Duration parseNullableDuration(final @Nullable String s,
final Duration defaultValue) {
if (s == null) {
return defaultValue;
}
return parseNullableDuration(s);
}
public static String serNullableDuration(final @Nullable Duration duration) {
if (duration == null) {
return "-1"; // for backward compatibility //$NON-NLS-1$
}
return Long.toString(duration.toMillis());
}
private Utils() {
}
......