blob: b8ac23b49d0112c8667dffef3aed48f6be2f14ed [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2021 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 static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullLateInit;
import static org.eclipse.statet.rj.servi.RServiUtils.RJ_SERVI_ID;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.RemoteServer;
import java.rmi.server.ServerNotActiveException;
import java.rmi.server.UnicastRemoteObject;
import java.util.concurrent.ExecutorService;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
import org.eclipse.statet.jcommons.collections.CopyOnWriteList;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.runtime.CommonsRuntime;
import org.eclipse.statet.jcommons.status.ErrorStatus;
import org.eclipse.statet.rj.servi.node.RServiNode;
@NonNullByDefault
public class APool2NodeFactory implements PooledObjectFactory<APool2NodeHandler> {
private APool2 pool= nonNullLateInit();
private final NodeFactory nodeFactory;
private final CopyOnWriteList<APool2NodeHandler> nodes= new CopyOnWriteList<>();
private final CopyOnWriteIdentityListSet<PoolListener> poolListeners;
private int statMaxTotal;
private int statMaxAllocated;
private int maxUsageCount;
private @Nullable RMIClientSocketFactory sslClientSocketFactory;
private @Nullable RMIServerSocketFactory sslServerSocketFactory;
private final ThreadLocal<String> activateArguments= new ThreadLocal<>();
private final ExecutorService executor;
public APool2NodeFactory(final NodeFactory factory,
final CopyOnWriteIdentityListSet<PoolListener> poolListeners,
final ExecutorService executor) {
this.nodeFactory= factory;
this.executor= executor;
this.poolListeners= poolListeners;
}
void setPool(final APool2 pool) {
this.pool= pool;
}
public void setMaxUsageCount(final int count) {
this.maxUsageCount= count;
}
public int getNumAll() {
return this.nodes.size();
}
public ImList<APool2NodeHandler> getAllObjects() {
return this.nodes.toList();
}
@Override
public PooledObject<APool2NodeHandler> makeObject() throws Exception {
// start
final APool2NodeHandler poolObj= new APool2NodeHandler(this.pool);
synchronized (this.nodes) {
this.nodes.add(poolObj);
final int total= this.nodes.size();
if (total > this.statMaxTotal) {
this.statMaxTotal= total;
}
}
boolean ok= false;
try {
if (!this.pool.isOpen()) {
throw new IllegalStateException("Pool not open");
}
for (final PoolListener listener : this.poolListeners.toList()) {
try {
listener.initializing(poolObj);
}
catch (final Exception e) {
onErrorInListener(listener, e);
}
}
this.nodeFactory.createNode(poolObj);
{ RMIClientSocketFactory clientSocketFactory= null;
RMIServerSocketFactory serverSocketFactory= null;
if (poolObj.address.isSsl()) {
synchronized (this) {
if (this.sslClientSocketFactory == null) {
this.sslClientSocketFactory= new SslRMIClientSocketFactory();
this.sslServerSocketFactory= new SslRMIServerSocketFactory(null, null, true);
}
clientSocketFactory= this.sslClientSocketFactory;
serverSocketFactory= this.sslServerSocketFactory;
}
}
poolObj.thisRemote= UnicastRemoteObject.exportObject(poolObj, 0,
clientSocketFactory, serverSocketFactory );
}
for (final PoolListener listener : this.poolListeners.toList()) {
try {
listener.initialized(poolObj);
}
catch (final Exception e) {
onErrorInListener(listener, e);
}
}
ok= true;
return poolObj.getPooledObject();
}
finally {
if (!ok) {
destroyObject(poolObj.getPooledObject());
}
}
}
public void registerArgs(final String client) {
this.activateArguments.set(client);
}
public void clearArgs() {
this.activateArguments.remove();
}
@Override
public void activateObject(final PooledObject<APool2NodeHandler> p) throws Exception {
synchronized (this) {
final int numAllocated= this.pool.getNumActive();
if (numAllocated > this.statMaxAllocated) {
this.statMaxAllocated= numAllocated;
}
}
final String name= this.activateArguments.get();
final APool2NodeHandler poolObj= p.getObject();
final RServiNode node= nonNullAssert(poolObj.node);
String clientHost;
try {
clientHost= RemoteServer.getClientHost();
}
catch (final ServerNotActiveException e) {
clientHost= node.getPoolHost();
}
poolObj.bindClient(name, clientHost);
}
@Override
public void passivateObject(final PooledObject<APool2NodeHandler> p) throws Exception {
final APool2NodeHandler poolObj= p.getObject();
poolObj.unbindClient();
}
@Override
public boolean validateObject(final PooledObject<APool2NodeHandler> p) {
final APool2NodeHandler poolObj= p.getObject();
if (poolObj.isEvictRequested(0)) {
return false;
}
final int max= this.maxUsageCount;
if (max > 0 && ((DefaultPooledObject<?>) p).getBorrowedCount() >= max) {
poolObj.stats.shutdownReason= Stats.MAX_USAGE;
return false;
}
return true;
}
@Override
public void destroyObject(final PooledObject<APool2NodeHandler> p) throws Exception {
final APool2NodeHandler poolObj= p.getObject();
try {
if (poolObj.thisRemote != null) {
try {
poolObj.thisRemote= null;
UnicastRemoteObject.unexportObject(poolObj, true);
}
catch (final Throwable e) {
Utils.logError(Messages.RmiUnexportNode_error_message, e);
}
}
}
finally {
this.executor.submit(new Runnable() {
@Override
public void run() {
try {
try {
APool2NodeFactory.this.nodeFactory.stopNode(poolObj);
}
finally {
for (final PoolListener listener : APool2NodeFactory.this.poolListeners.toList()) {
try {
listener.disposed(poolObj);
}
catch (final Exception e) {
onErrorInListener(listener, e);
}
}
}
}
finally {
APool2NodeFactory.this.nodes.remove(poolObj);
}
}
});
}
}
public int getStatMaxTotal() {
return this.statMaxTotal;
}
public int getStatMaxAllocated() {
return this.statMaxAllocated;
}
private void onErrorInListener(final PoolListener listener, final Exception e) {
CommonsRuntime.log(new ErrorStatus(RJ_SERVI_ID,
String.format("An error occurred in pool listener (%1$s) of '%2$s'.",
listener.getClass().getSimpleName(), this.pool.getId() ),
e ));
}
}