Skip to content
This repository has been archived by the owner on Aug 11, 2020. It is now read-only.

Commit

Permalink
Merge pull request #568 from sonatype/hc4provider-jmx
Browse files Browse the repository at this point in the history
Register pooling conn manager into mmx
  • Loading branch information
adreghiciu committed Oct 10, 2012
2 parents e3fbe54 + 27ae8ef commit 29cb7ce
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 5 deletions.
Expand Up @@ -151,6 +151,11 @@ public class Hc4ProviderImpl
*/
private final EvictingThread evictingThread;

/**
* Used to install created {@link PoolingClientConnectionManager} into jmx.
*/
private final PoolingClientConnectionManagerMBeanInstaller jmxInstaller;

/**
* Constructor.
*
Expand All @@ -160,17 +165,20 @@ public class Hc4ProviderImpl
*/
@Inject
public Hc4ProviderImpl( final ApplicationConfiguration applicationConfiguration,
final UserAgentBuilder userAgentBuilder, final ApplicationEventMulticaster multicaster )
final UserAgentBuilder userAgentBuilder, final ApplicationEventMulticaster multicaster,
final PoolingClientConnectionManagerMBeanInstaller jmxInstaller )
{
this.applicationConfiguration = Preconditions.checkNotNull( applicationConfiguration );
this.userAgentBuilder = Preconditions.checkNotNull( userAgentBuilder );
this.jmxInstaller = Preconditions.checkNotNull( jmxInstaller );
this.sharedConnectionManager = createClientConnectionManager();
this.evictingThread = new EvictingThread( sharedConnectionManager, getConnectionPoolKeepalive() );
this.evictingThread.start();
this.applicationEventMulticaster = Preconditions.checkNotNull( multicaster );
this.applicationEventMulticaster.addEventListener( this );
this.jmxInstaller.register( sharedConnectionManager );
getLogger().info( "{} started up (keep-alive {} millis), listening for shutdown.", getClass().getSimpleName(),
getConnectionPoolKeepalive() );
getConnectionPoolKeepalive() );
}

// configuration
Expand Down Expand Up @@ -259,6 +267,7 @@ protected int getSoTimeout( final RemoteStorageContext context )
public synchronized void shutdown()
{
evictingThread.interrupt();
jmxInstaller.unregister();
sharedConnectionManager.shutdown();
applicationEventMulticaster.removeEventListener( this );
getLogger().info( "{} shut down.", getClass().getSimpleName() );
Expand Down
@@ -0,0 +1,45 @@
/**
* Sonatype Nexus (TM) Open Source Version
* Copyright (c) 2007-2012 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
* which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
* of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
* Eclipse Foundation. All other trademarks are the property of their respective owners.
*/
package org.sonatype.nexus.apachehttpclient;

import org.apache.http.impl.conn.PoolingClientConnectionManager;

/**
* MBean which exposes details about a {@link PoolingClientConnectionManager}.
*
* @since 2.2
*/
public interface PoolingClientConnectionManagerMBean
{

int getMaxTotal();

int getDefaultMaxPerRoute();

int getLeased();

int getPending();

int getAvailable();

int getMax();

void closeIdleConnections( long idleTimeoutInMillis );

void closeExpiredConnections();

void setMaxTotal( int max );

void setDefaultMaxPerRoute( int max );

}
@@ -0,0 +1,100 @@
/**
* Sonatype Nexus (TM) Open Source Version
* Copyright (c) 2007-2012 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
* which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
* of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
* Eclipse Foundation. All other trademarks are the property of their respective owners.
*/
package org.sonatype.nexus.apachehttpclient;

import java.util.concurrent.TimeUnit;
import javax.management.StandardMBean;

import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.sonatype.appcontext.internal.Preconditions;

/**
* Default {@link PoolingClientConnectionManagerMBean} implementation.
*
* @since 2.2
*/
class PoolingClientConnectionManagerMBeanImpl
extends StandardMBean
implements PoolingClientConnectionManagerMBean
{

private final PoolingClientConnectionManager connMgr;

PoolingClientConnectionManagerMBeanImpl( final PoolingClientConnectionManager connMgr )
{
super( PoolingClientConnectionManagerMBean.class, false );

this.connMgr = Preconditions.checkNotNull( connMgr );
}

@Override
public int getMaxTotal()
{
return connMgr.getMaxTotal();
}

@Override
public int getDefaultMaxPerRoute()
{
return connMgr.getDefaultMaxPerRoute();
}

@Override
public int getLeased()
{
return connMgr.getTotalStats().getLeased();
}

@Override
public int getPending()
{
return connMgr.getTotalStats().getPending();
}

@Override
public int getAvailable()
{
return connMgr.getTotalStats().getAvailable();
}

@Override
public int getMax()
{
return connMgr.getTotalStats().getMax();
}

@Override
public void closeIdleConnections( final long idleTimeoutInMillis )
{
connMgr.closeIdleConnections( idleTimeoutInMillis, TimeUnit.MILLISECONDS );
}

@Override
public void closeExpiredConnections()
{
connMgr.closeExpiredConnections();
}

@Override
public void setMaxTotal( final int max )
{
connMgr.setMaxTotal( max );
}

@Override
public void setDefaultMaxPerRoute( final int max )
{
connMgr.setDefaultMaxPerRoute( max );
}

}
@@ -0,0 +1,94 @@
/**
* Sonatype Nexus (TM) Open Source Version
* Copyright (c) 2007-2012 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
* which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
* of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
* Eclipse Foundation. All other trademarks are the property of their respective owners.
*/
package org.sonatype.nexus.apachehttpclient;

import java.lang.management.ManagementFactory;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* An wrapper {@link Hc4Provider} that automatically registers / unregisters JMX MBeans for each created
* {@link HttpClient}s and {@link PoolingClientConnectionManager}.
*
* @since 2.2
*/
@Named()
@Singleton
public class PoolingClientConnectionManagerMBeanInstaller
{

private static final Logger LOGGER = LoggerFactory.getLogger( PoolingClientConnectionManagerMBeanInstaller.class );

private static final String JMX_DOMAIN = "org.sonatype.nexus.httpclient";

private ObjectName jmxName;

public synchronized void register( final PoolingClientConnectionManager connectionManager )
{
if ( jmxName == null )
{
try
{
jmxName = ObjectName.getInstance(
JMX_DOMAIN, "name", PoolingClientConnectionManager.class.getSimpleName()
);

final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
server.registerMBean( new PoolingClientConnectionManagerMBeanImpl( connectionManager ), jmxName );
}
catch ( final Exception e )
{
LOGGER.warn(
"Failed to register mbean {} due to {}:{}",
new Object[]{ jmxName, e.getClass(), e.getMessage() }
);
jmxName = null;
}
}
else
{
LOGGER.warn( "Already registered mbean {}", jmxName );
}
}

public synchronized void unregister()
{
if ( jmxName != null )
{
try
{
final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
server.unregisterMBean( jmxName );
}
catch ( final Exception e )
{
LOGGER.warn(
"Failed to unregister mbean {} due to {}:{}",
new Object[]{ jmxName, e.getClass(), e.getMessage() }
);
}
finally
{
jmxName = null;
}
}
}

}
Expand Up @@ -50,6 +50,9 @@ public class Hc4ProviderImplTest
@Mock
private RemoteStorageContext globalRemoteStorageContext;

@Mock
private PoolingClientConnectionManagerMBeanInstaller jmxInstaller;

@Before
public void prepare()
{
Expand All @@ -66,7 +69,7 @@ public void sharedInstanceConfigurationTest()
setParameters();
try
{
testSubject = new Hc4ProviderImpl( applicationConfiguration, userAgentBuilder, multicaster );
testSubject = new Hc4ProviderImpl( applicationConfiguration, userAgentBuilder, multicaster, jmxInstaller );

final HttpClient client = testSubject.createHttpClient();
// Note: shared instance is shared across Nexus instance. It does not features connection pooling as
Expand Down Expand Up @@ -97,7 +100,7 @@ public void createdInstanceConfigurationTest()
setParameters();
try
{
testSubject = new Hc4ProviderImpl( applicationConfiguration, userAgentBuilder, multicaster );
testSubject = new Hc4ProviderImpl( applicationConfiguration, userAgentBuilder, multicaster, jmxInstaller );

// Note: explicitly created instance (like in case of proxies), it does pool and
// returns customized client
Expand Down
Expand Up @@ -25,6 +25,7 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonatype.nexus.ApplicationStatusSource;
import org.sonatype.nexus.apachehttpclient.PoolingClientConnectionManagerMBeanInstaller;
import org.sonatype.nexus.configuration.application.ApplicationConfiguration;
import org.sonatype.nexus.apachehttpclient.Hc4ProviderImpl;
import org.sonatype.nexus.mime.MimeSupport;
Expand Down Expand Up @@ -172,7 +173,8 @@ public void emitProperExceptionOnPoolDepletion()
// real provider and initializing it with NexusStarted event
hc4Provider =
new Hc4ProviderImpl( applicationConfiguration, mock( UserAgentBuilder.class ),
mock( ApplicationEventMulticaster.class ) );
mock( ApplicationEventMulticaster.class ),
mock( PoolingClientConnectionManagerMBeanInstaller.class ) );

// the RRS instance we test
final HttpClientRemoteStorage underTest =
Expand Down

0 comments on commit 29cb7ce

Please sign in to comment.