blob: 45b337d18ab93dec454532ddd9f1cfcdee4a57ff [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2018 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.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 java.util.concurrent.Executors;
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;
public class APool2NodeFactory implements PooledObjectFactory<APool2NodeHandler> {
private APool2 pool;
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 RMIClientSocketFactory sslClientSocketFactory;
private RMIServerSocketFactory sslServerSocketFactory;
private final ThreadLocal<String> activateArguments= new ThreadLocal<>();
private final ExecutorService executor= Executors.newSingleThreadExecutor();
public APool2NodeFactory(final NodeFactory factory,
final CopyOnWriteIdentityListSet<PoolListener> poolListeners) {
this.nodeFactory= factory;
this.poolListeners= poolListeners;
}
void setPool(final APool2 pool) {
this.pool= pool;
}
void dispose() {
this.executor.shutdown();
}
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 {
for (final PoolListener listener : this.poolListeners.toList()) {
try {
listener.initializing(poolObj);
}
catch (final Exception e) {
e.printStackTrace(); // TODO
}
}
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) {
e.printStackTrace(); // TODO
}
}
ok= true;
return poolObj.getPooledObject();
}
finally {
if (!ok) {
this.nodes.remove(poolObj);
}
}
}
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();
String clientHost;
try {
clientHost= RemoteServer.getClientHost();
}
catch (final ServerNotActiveException e) {
clientHost= poolObj.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.logWarning(Messages.RmiUnexportNode_error_message, e);
}
}
}
finally {
this.executor.submit(new Runnable() {
@Override
public void run() {
try {
APool2NodeFactory.this.nodeFactory.stopNode(poolObj);
for (final PoolListener listener : APool2NodeFactory.this.poolListeners.toList()) {
try {
listener.disposed(poolObj);
}
catch (final Exception e) {
e.printStackTrace(); // TODO
}
}
}
finally {
APool2NodeFactory.this.nodes.remove(poolObj);
}
}
});
}
}
public int getStatMaxTotal() {
return this.statMaxTotal;
}
public int getStatMaxAllocated() {
return this.statMaxAllocated;
}
}