blob: 936a1504018719dae5d28d7bc7605889af927ddd [file] [log] [blame]
/*
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package amxtest;
import java.util.Properties;
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.net.MalformedURLException;
import java.io.IOException;
import org.testng.Reporter;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import org.testng.annotations.Configuration;
import org.testng.annotations.ExpectedExceptions;
import org.testng.annotations.Test;
import org.testng.annotations.*;
import org.testng.Assert;
import javax.management.ObjectName;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.MBeanServerDelegateMBean;
import javax.management.MBeanServerNotification;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import org.glassfish.admin.amx.base.*;
import org.glassfish.admin.amx.core.*;
import org.glassfish.admin.amx.core.proxy.ProxyFactory;
import org.glassfish.admin.amx.config.AMXConfigProxy;
import org.glassfish.admin.amx.util.TimingDelta;
import org.glassfish.admin.amx.util.ListUtil;
import org.glassfish.admin.amx.util.ExceptionUtil;
import org.glassfish.admin.amx.util.jmx.JMXUtil;
import org.glassfish.external.amx.AMXGlassfish;
/** The base class for AMX tests
*/
public class AMXTestBase
{
String mAdminUser;
String mAdminPassword;
String mHost;
int mPort;
boolean mDebug;
private volatile MBeanServerConnection mMBeanServerConnection;
private volatile ProxyFactory mProxyFactory;
private volatile DomainRoot mDomainRoot;
private volatile Query mQueryMgr;
protected static void debug(final String s)
{
System.out.println("" + s);
}
protected static void println(final String s)
{
System.out.println("" + s);
}
protected static void warning(final String s)
{
System.out.println("" + s);
}
AMXTestBase()
{
//debug("################################ AMXTestBase");
}
// might need these later: "admin.user", "admin.password"
@BeforeClass(description = "get setup and connect to the MBeanServer")
@Parameters(
{
"amx.debug", "amx.rmiport"
})
void setUpEnvironment(
final boolean debug,
final int port)
{
// defined in top-level build.xml
mHost = System.getProperty("http.host");
mDebug = debug;
mPort = port;
try
{
setup();
}
catch (Exception ex)
{
debug("AMXTestBase: Exception in setting up env. = " + ex);
ex.printStackTrace();
}
}
static final class MBeansListener implements NotificationListener
{
private final MBeanServerConnection mServer;
private final String mDomain;
private final List<ObjectName> mRegistered = Collections.synchronizedList(new ArrayList<ObjectName>());
private final List<ObjectName> mUnregistered = Collections.synchronizedList(new ArrayList<ObjectName>());
public MBeansListener(final MBeanServerConnection server, final String domain)
{
mServer = server;
mDomain = domain;
}
public void startListening()
{
final ObjectName delegate = JMXUtil.newObjectName( JMXUtil.MBEAN_SERVER_DELEGATE );
try
{
mServer.addNotificationListener( delegate, this, null, null);
}
catch( final Exception e )
{
throw new RuntimeException(e);
}
}
public void handleNotification(
final Notification notif,
final Object handback)
{
if ( ! (notif instanceof MBeanServerNotification) )
{
return;
}
final MBeanServerNotification mbs = (MBeanServerNotification)notif;
final ObjectName objectName = mbs.getMBeanName();
if ( "*".equals(mDomain) || mDomain.equals(objectName.getDomain()) )
{
if ( mbs.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION ) )
{
//debug( "Registered: " + objectName );
mRegistered.add( objectName );
}
else if ( mbs.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION ) )
{
//debug( "Unregistered: " + objectName );
mUnregistered.add( objectName );
}
}
}
}
private static MBeansListener sMBeansListener = null;
protected synchronized void getMBeansListener() throws Exception
{
if ( sMBeansListener == null )
{
sMBeansListener = new MBeansListener(mMBeanServerConnection, mDomainRoot.objectName().getDomain());
sMBeansListener.startListening();
}
}
private static boolean sEnabledMonitoring = false;
/**
Subclasses may override if desired. AMX will have been started
and initialized already.
*/
protected void setup()
{
//debug("################################ AMXTestBase.setup");
final TimingDelta timing = new TimingDelta();
final TimingDelta overall = new TimingDelta();
try
{
mMBeanServerConnection = _getMBeanServerConnection();
mProxyFactory = ProxyFactory.getInstance(mMBeanServerConnection);
//debug( "AMXTestBase.setup(): millis to connect: " + timing.elapsedMillis() );
mDomainRoot = _getDomainRoot(mMBeanServerConnection);
//debug( "AMXTestBase.setup(): millis to boot AMX: " + timing.elapsedMillis() );
mQueryMgr = getDomainRootProxy().getQueryMgr();
//debug( "AMXTestBase.setup(): millis to get QueryMgr: " + timing.elapsedMillis() );
getMBeansListener();
}
catch (Exception e)
{
e.printStackTrace();
throw new RuntimeException(e);
}
//debug( "AMXTestBase.setup(): total setup millis: " + overall.elapsedMillis() );
}
protected final Query getQueryMgr()
{
return mQueryMgr;
}
/** get all AMX MBeans that were found when the test started
Caller should use the QueryMgr if a fresh set is needed */
protected Set<AMXProxy> getAllAMX()
{
final Set<AMXProxy> allAMX = getQueryMgr().queryAll();
assert allAMX.size() >= 30;
return allAMX;
}
protected <T> Set<T> getAll(final Class<T> intf)
{
return getAll(getAllAMX(), intf);
}
protected <T> Set<T> getAll(final Set<AMXProxy> all, final Class<T> intf)
{
final Set<T> result = new HashSet<T>();
for (final AMXProxy amx : all)
{
if (intf.isAssignableFrom(amx.getClass()))
{
result.add(intf.cast(amx));
}
}
return result;
}
protected final DomainRoot getDomainRootProxy()
{
return mDomainRoot;
}
protected final Ext getExt() { return getDomainRootProxy().getExt(); }
protected ProxyFactory getProxyFactory() { return mProxyFactory; }
protected final DomainRoot _getDomainRoot(final MBeanServerConnection conn)
throws MalformedURLException, IOException, java.net.MalformedURLException
{
final ObjectName domainRootObjectName = AMXGlassfish.DEFAULT.bootAMX(conn);
final DomainRoot domainRoot = getProxyFactory().getDomainRootProxy();
return domainRoot;
}
protected final MBeanServerConnection getMBeanServerConnection() { return mMBeanServerConnection; }
private final MBeanServerConnection _getMBeanServerConnection()
throws MalformedURLException, IOException
{
// service:jmx:rmi:///jndi/rmi://192.168.1.8:8686/jmxrmi
// service:jmx:jmxmp://localhost:8888
// CHANGE to RMI once it's working
//
// final String urlStr = "service:jmx:jmxmp://" + mHost + ":" + mPort;
final String urlStr = "service:jmx:rmi:///jndi/rmi://" + mHost + ":" + mPort + "/jmxrmi";
final long start = System.currentTimeMillis();
final JMXServiceURL url = new JMXServiceURL(urlStr);
final JMXConnector jmxConn = JMXConnectorFactory.connect(url);
//debug( "BaseAMXTest: connecting to: " + url );
final MBeanServerConnection conn = jmxConn.getMBeanServerConnection();
conn.getDomains(); // sanity check
try
{
final ObjectName domainRootObjectName = AMXGlassfish.DEFAULT.bootAMX(conn);
}
catch( final Exception e )
{
System.err.println( ExceptionUtil.toString(ExceptionUtil.getRootCause(e)) );
}
//System.out.println( "Got connection, verified connectivity: " + (System.currentTimeMillis() - start));
return conn;
}
protected static final String NL = System.getProperty("line.separator");
protected static String getEnvString()
{
final Properties props = System.getProperties();
final StringBuilder buf = new StringBuilder();
buf.append("SYSTEM PROPERTIES:" + NL);
for (final Object key : props.keySet())
{
buf.append(key);
buf.append(" = ");
buf.append("" + props.get(key) + NL);
}
final String result = buf.toString();
return result;
}
/** subclass can override to add more */
protected Interfaces getInterfaces()
{
return haveJSR77() ? new InterfacesGlassfish() : new Interfaces();
}
/** must be checked dynamically because it's not in the web distribution */
protected static final Class<? extends AMXProxy> getJ2EEDomainClass()
throws ClassNotFoundException
{
return Class.forName( "org.glassfish.admin.amx.j2ee.J2EEDomain" ).asSubclass(AMXProxy.class);
}
/** return true if we have the JSR 77 classes */
protected boolean haveJSR77()
{
try
{
getJ2EEDomainClass();
//System.out.println( "FOUND J2EEDomain" );
return true;
}
catch( final Exception e )
{
//System.out.println( "NOT FOUND J2EEDomain" );
}
return false;
}
protected Set<AMXProxy> findAllContainingType( final String type )
{
final Set<AMXProxy> all = getQueryMgr().queryAll();
final Set<AMXProxy> parentsWith = new HashSet<AMXProxy>();
for( final AMXProxy amx : all )
{
if ( amx.type().equals(type) )
{
final AMXProxy parent = amx.parent();
parentsWith.add(parent);
}
}
return parentsWith;
}
protected <T extends AMXProxy> List<T> getAllDescendents( final AMXProxy top, final Class<T> clazz)
{
final AMXProxy[] a = getQueryMgr().queryDescendants( top.objectName() );
final List<AMXProxy> list = ListUtil.newListFromArray(a);
return Util.asProxyList( list, clazz );
}
List<AMXProxy> getAllMonitoring()
{
return getAllDescendents( getDomainRootProxy().getMonitoringRoot(), AMXProxy.class);
}
}