/**
* Copyright 2014 SAP AG
*
* Licensed 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.spotter.ext.measurement.jmsserver;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import org.aim.api.exceptions.MeasurementException;
import org.aim.api.measurement.MeasurementData;
import org.aim.api.measurement.collector.AbstractDataSource;
import org.aim.api.measurement.collector.CollectorFactory;
import org.aim.artifacts.measurement.collector.FileDataSource;
import org.aim.artifacts.records.JmsServerRecord;
import org.aim.description.InstrumentationDescription;
import org.aim.description.sampling.SamplingDescription;
import org.apache.activemq.broker.jmx.BrokerViewMBean;
import org.apache.activemq.broker.jmx.QueueViewMBean;
import org.lpe.common.config.GlobalConfiguration;
import org.lpe.common.extension.IExtension;
import org.lpe.common.util.system.LpeSystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spotter.core.measurement.AbstractMeasurementAdapter;
/**
* Measurement adapter for sampling status of a JMS Server.
*
* @author Alexander Wert
*
*/
public class JmsServerMeasurement extends AbstractMeasurementAdapter implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(JmsServerMeasurement.class);
public static final String DESTINATION_NAME = "org.spotter.measurement.jmsserver.DestinationName";
public static final String ACTIVE_MQJMX_URL = "org.spotter.measurement.jmsserver.ActiveMQJMXUrl";
private AbstractDataSource dataSource;
private Future<?> measurementTask;
private List<QueueViewMBean> queueMbeans;
private BrokerViewMBean mbean;
private boolean running;
private boolean samplerActivated = false;
private boolean messagingServerAvailable = false;
private long delay;
protected static final long DEFAULT_DELAY = 500;
/**
* Constructor.
*
* @param provider
* extension provider
*/
public JmsServerMeasurement(IExtension<?> provider) {
super(provider);
}
@Override
public void enableMonitoring() throws MeasurementException {
if (samplerActivated && messagingServerAvailable) {
resetActiveMQStatistics();
measurementTask = LpeSystemUtils.submitTask(this);
}
}
@Override
public void disableMonitoring() throws MeasurementException {
if (samplerActivated && messagingServerAvailable) {
try {
running = false;
measurementTask.get();
} catch (InterruptedException | ExecutionException e) {
throw new MeasurementException(e);
}
}
}
private void resetActiveMQStatistics() {
try {
LOGGER.debug("purge and reset ActiveMQ server");
for (QueueViewMBean queueMbean : queueMbeans) {
// queueMbean.purge();
queueMbean.resetStatistics();
}
mbean.resetStatistics();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public MeasurementData getMeasurementData() throws MeasurementException {
if (samplerActivated && messagingServerAvailable) {
return dataSource.read();
} else {
return new MeasurementData();
}
}
@Override
public void pipeToOutputStream(OutputStream oStream) throws MeasurementException {
if (samplerActivated && messagingServerAvailable) {
dataSource.pipeToOutputStream(oStream);
} else {
try {
oStream.close();
} catch (IOException e) {
throw new MeasurementException(e);
}
}
}
@Override
public void initialize() throws MeasurementException {
Properties collectorProperties = GlobalConfiguration.getInstance().getProperties();
collectorProperties.setProperty(FileDataSource.ADDITIONAL_FILE_PREFIX_KEY, "JMSServerSampler");
dataSource = CollectorFactory.createDataSource(FileDataSource.class.getName(), collectorProperties);
try {
LOGGER.debug("Connect to JMX ActiveMQ server");
String activeMqJMX = getProperties().getProperty(ACTIVE_MQJMX_URL);
JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL(activeMqJMX));
connector.connect();
MBeanServerConnection connection = connector.getMBeanServerConnection();
ObjectName mbeanName = new ObjectName("org.apache.activemq:type=Broker,brokerName=myBroker");
mbean = MBeanServerInvocationHandler.newProxyInstance(connection, mbeanName, BrokerViewMBean.class, true);
queueMbeans = new ArrayList<>();
for (ObjectName queueName : mbean.getQueues()) {
QueueViewMBean tempQueueMbean = (QueueViewMBean) MBeanServerInvocationHandler.newProxyInstance(
connection, queueName, QueueViewMBean.class, true);
queueMbeans.add(tempQueueMbean);
}
messagingServerAvailable = true;
} catch (Exception e) {
LOGGER.error("Messaging Server not available!");
messagingServerAvailable = false;
}
}
@Override
public long getCurrentTime() {
return System.currentTimeMillis();
}
@Override
public void run() {
running = true;
try {
dataSource.enable();
while (running) {
sampleJmsServerStatistics();
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {
LOGGER.debug("Sleeptime interrupted.");
running = false;
}
}
dataSource.disable();
} catch (MeasurementException e) {
throw new RuntimeException(e);
}
}
/**
* Samples JMS Server status
*/
private void sampleJmsServerStatistics() {
for (QueueViewMBean tempBean : queueMbeans) {
JmsServerRecord record = new JmsServerRecord();
record.setQueueName(tempBean.getName());
record.setTimeStamp(System.currentTimeMillis());
record.setAverageEnqueueTime(tempBean.getAverageEnqueueTime());
record.setDequeueCount(tempBean.getDequeueCount());
record.setDispatchCount(tempBean.getDispatchCount());
record.setEnqueueCount(tempBean.getEnqueueCount());
record.setMemoryPercentUsage(tempBean.getMemoryPercentUsage());
record.setMemoryUsage(tempBean.getMemoryUsageByteCount());
record.setQueueSize(tempBean.getQueueSize());
record.setAvgMessageSize(mbean.getAverageMessageSize());
dataSource.newRecord(record);
}
}
@Override
public void storeReport(String path) throws MeasurementException {
// nothing to do here.
}
@Override
public void prepareMonitoring(InstrumentationDescription monitoringDescription) throws MeasurementException {
for (SamplingDescription sDescr : monitoringDescription.getSamplingDescriptions()) {
if (sDescr.getResourceName().equals(SamplingDescription.SAMPLER_MESSAGING_STATISTICS)) {
samplerActivated = true;
delay = sDescr.getDelay();
break;
}
}
}
@Override
public void resetMonitoring() throws MeasurementException {
samplerActivated = false;
}
}