/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.core;
import java.lang.management.ManagementFactory;
import java.util.*;
import javax.management.*;
import org.apache.lucene.util.Constants;
import org.apache.solr.core.JmxMonitoredMap.SolrDynamicMBean;
import org.apache.solr.util.AbstractSolrTestCase;
import org.junit.Assume;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
/**
* Test for JMX Integration
*
*
* @since solr 1.3
*/
public class TestJmxIntegration extends AbstractSolrTestCase {
private static MBeanServer mbeanServer = null;
@BeforeClass
public static void beforeClass() throws Exception {
// Make sure that at least one MBeanServer is available
// prior to initializing the core
//
// (test configs are setup to use existing server if any,
// otherwise skip JMX)
MBeanServer platformServer = ManagementFactory.getPlatformMBeanServer();
initCore("solrconfig.xml", "schema.xml");
// we should be able to se that the core has JmxIntegration enabled
assertTrue("JMX not enabled",
h.getCore().getSolrConfig().jmxConfig.enabled);
// and we should be able to see that the the monitor map found
// a JMX server to use, which refers to the server we started
Map registry = h.getCore().getInfoRegistry();
assertTrue("info registry is not a JMX monitored map",
registry instanceof JmxMonitoredMap);
mbeanServer = ((JmxMonitoredMap)registry).getServer();
assertNotNull("No JMX server found by monitor map",
mbeanServer);
// NOTE: we can't garuntee that "mbeanServer == platformServer"
// the JVM may have mutiple MBean servers funning when the test started
// and the contract of not specifying one when configuring solr with
// <jmx /> is that it will use whatever the "first" MBean server
// returned by the JVM is.
}
@AfterClass
public static void afterClass() throws Exception {
mbeanServer = null;
}
@Test
public void testJmxRegistration() throws Exception {
assertTrue("No MBeans found in server", mbeanServer.getMBeanCount() > 0);
Set<ObjectInstance> objects = mbeanServer.queryMBeans(null, null);
assertFalse("No objects found in mbean server", objects
.isEmpty());
int numDynamicMbeans = 0;
for (ObjectInstance o : objects) {
assertNotNull("Null name on: " + o.toString(), o.getObjectName());
MBeanInfo mbeanInfo = mbeanServer.getMBeanInfo(o.getObjectName());
if (mbeanInfo.getClassName().endsWith(SolrDynamicMBean.class.getName())) {
numDynamicMbeans++;
MBeanAttributeInfo[] attrs = mbeanInfo.getAttributes();
assertTrue("No Attributes found for mbean: " + mbeanInfo,
0 < attrs.length);
for (MBeanAttributeInfo attr : attrs) {
// ensure every advertised attribute is gettable
try {
Object trash = mbeanServer.getAttribute(o.getObjectName(), attr.getName());
} catch (javax.management.AttributeNotFoundException e) {
throw new RuntimeException("Unable to featch attribute for " + o.getObjectName()
+ ": " + attr.getName(), e);
}
}
}
}
assertTrue("No SolrDynamicMBeans found", 0 < numDynamicMbeans);
}
@Test
public void testJmxUpdate() throws Exception {
SolrInfoMBean bean = null;
// wait until searcher is registered
for (int i=0; i<100; i++) {
bean = h.getCore().getInfoRegistry().get("searcher");
if (bean != null) break;
Thread.sleep(250);
}
if (bean==null) throw new RuntimeException("searcher was never registered");
ObjectName searcher = getObjectName("searcher", bean);
log.info("Mbeans in server: " + mbeanServer.queryNames(null, null));
assertFalse("No mbean found for SolrIndexSearcher", mbeanServer.queryMBeans(searcher, null).isEmpty());
int oldNumDocs = (Integer)mbeanServer.getAttribute(searcher, "numDocs");
assertU(adoc("id", "1"));
assertU("commit", commit());
int numDocs = (Integer)mbeanServer.getAttribute(searcher, "numDocs");
assertTrue("New numDocs is same as old numDocs as reported by JMX",
numDocs > oldNumDocs);
}
@Test @Ignore("timing problem? https://issues.apache.org/jira/browse/SOLR-2715")
public void testJmxOnCoreReload() throws Exception {
String coreName = h.getCore().getName();
Set<ObjectInstance> oldBeans = mbeanServer.queryMBeans(null, null);
int oldNumberOfObjects = 0;
for (ObjectInstance bean : oldBeans) {
try {
if (String.valueOf(h.getCore().hashCode()).equals(mbeanServer.getAttribute(bean.getObjectName(), "coreHashCode"))) {
oldNumberOfObjects++;
}
} catch (AttributeNotFoundException e) {
// expected
}
}
log.info("Before Reload: Size of infoRegistry: " + h.getCore().getInfoRegistry().size() + " MBeans: " + oldNumberOfObjects);
assertEquals("Number of registered MBeans is not the same as info registry size", h.getCore().getInfoRegistry().size(), oldNumberOfObjects);
h.getCoreContainer().reload(coreName);
Set<ObjectInstance> newBeans = mbeanServer.queryMBeans(null, null);
int newNumberOfObjects = 0;
int registrySize = 0;
SolrCore core = h.getCoreContainer().getCore(coreName);
try {
registrySize = core.getInfoRegistry().size();
for (ObjectInstance bean : newBeans) {
try {
if (String.valueOf(core.hashCode()).equals(mbeanServer.getAttribute(bean.getObjectName(), "coreHashCode"))) {
newNumberOfObjects++;
}
} catch (AttributeNotFoundException e) {
// expected
}
}
} finally {
core.close();
}
log.info("After Reload: Size of infoRegistry: " + registrySize + " MBeans: " + newNumberOfObjects);
assertEquals("Number of registered MBeans is not the same as info registry size", registrySize, newNumberOfObjects);
}
private ObjectName getObjectName(String key, SolrInfoMBean infoBean)
throws MalformedObjectNameException {
Hashtable<String, String> map = new Hashtable<>();
map.put("type", key);
map.put("id", infoBean.getName());
String coreName = h.getCore().getName();
return ObjectName.getInstance(("solr" + (null != coreName ? "/" + coreName : "")), map);
}
}