| /*=============================================================================# |
| # 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 )); |
| } |
| |
| } |