blob: 41d30017f7bd851d25d4b29be273e633081ce020 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.rj.servi;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.Unreferenced;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.rj.RjException;
import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
import org.eclipse.statet.rj.servi.pool.PoolNodeState;
@NonNullByDefault
public class APool2NodeHandler extends NodeHandler implements PoolNodeObject,
RServiImpl.PoolRef, Unreferenced {
static final long safeNanos(final long nanos) {
return (nanos != 0) ? nanos : 1;
}
static final long evictNanos(final long timeoutMillis) {
long nanos= System.nanoTime();
if (timeoutMillis > 0) {
nanos+= timeoutMillis * 1_000_000L;
}
return safeNanos(nanos);
}
private final APool2 pool;
private final DefaultPooledObject<APool2NodeHandler> p;
private volatile long evict;
final Stats.NodeEntry stats= new Stats.NodeEntry();
@Nullable Remote thisRemote;
private volatile long accessId;
public APool2NodeHandler(final APool2 pool) {
this.pool= pool;
this.p= new DefaultPooledObject<>(this);
}
@Override
public NodeHandler getNodeHandler() {
return this;
}
PooledObject<APool2NodeHandler> getPooledObject() {
return this.p;
}
@Override
public long getCreationTime() {
return this.p.getCreateTime();
}
@Override
public long getAllocatedCount() {
return this.p.getBorrowedCount();
}
@Override
public long getAllocatedDuration() {
return this.p.getActiveTimeMillis();
}
@Override
public PoolNodeState getState() {
if (this.node == null) {
switch (this.p.getState()) {
case IDLE:
return PoolNodeState.INITIALIZING;
case INVALID:
return PoolNodeState.DISPOSED;
default:
break;
}
}
switch(this.p.getState()) {
case IDLE:
return PoolNodeState.IDLING;
case ALLOCATED:
return PoolNodeState.ALLOCATED;
default:
return PoolNodeState.CHECKING;
}
}
@Override
public long getStateTime() {
switch (getState()) {
case INITIALIZING:
return getStartTime();
case ALLOCATED:
return this.p.getLastBorrowTime();
case CHECKING:
case IDLING:
return this.p.getLastReturnTime();
case DISPOSED:
return getShutdownTime();
default:
return -1;
}
}
@Override
void bindClient(final String name, final String host) throws RemoteException {
super.bindClient(name, host);
synchronized (this) {
this.accessId= this.p.getBorrowedCount();
}
}
void invalidateClient() {
this.accessId= -1L;
setClientLabel(null);
}
@Override
void unbindClient() throws RemoteException {
synchronized (this) {
invalidateClient();
}
super.unbindClient();
}
@Override
public void evict(final long timeout) {
doEvict(evictNanos(timeout), timeout == 0);
}
void doEvict(final long nanos, final boolean direct) {
synchronized (this.p) {
if (this.evict == 0 || this.evict > nanos) {
this.evict= safeNanos(nanos);
}
}
if (direct) {
try {
this.pool.invalidateObject(this);
}
catch (final Exception e) {}
}
}
boolean isEvictRequested(final long nanos) {
final long evict= this.evict;
return (evict != 0
&& (nanos == 0 || nanos >= evict) );
}
long getAccessId() {
final long accessId= this.accessId;
if (accessId == -1L) {
throw new IllegalAccessError();
}
return accessId;
}
@Override
public void returnObject(final long accessId) throws RjException {
try {
synchronized (this) {
if (this.accessId != accessId) {
throw new IllegalStateException("Access id no longer valid.");
}
invalidateClient();
}
this.pool.returnObject(this);
}
catch (final Exception e) {
Utils.logError("An unexpected error occurred when returning RServi instance.", e);
throw new RjException("An unexpected error occurred when closing RServi instance. See server log for detail.");
}
}
@Override
public void unreferenced() {
final PoolNodeState state= getState();
synchronized (this) {
if (state != PoolNodeState.ALLOCATED || this.accessId == -1L) {
return;
}
invalidateClient();
}
Utils.logInfo("The RServi instance is lent and unreferenced. It will be returned now.");
try {
this.pool.returnObject(this);
}
catch (final Exception e) {
Utils.logError("An unexpected error occurred when returning RServi instance.", e);
}
}
}