/**
* 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.activemq.broker.jmx;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.jms.Connection;
import javax.jms.InvalidSelectorException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.broker.jmx.OpenTypeSupport.OpenTypeFactory;
import org.apache.activemq.broker.region.Destination;
import org.apache.activemq.broker.region.Subscription;
import org.apache.activemq.broker.region.policy.AbortSlowConsumerStrategy;
import org.apache.activemq.broker.region.policy.SlowConsumerStrategy;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.command.ActiveMQMessage;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.apache.activemq.command.Message;
import org.apache.activemq.filter.BooleanExpression;
import org.apache.activemq.filter.MessageEvaluationContext;
import org.apache.activemq.selector.SelectorParser;
import org.apache.activemq.store.MessageStore;
import org.apache.activemq.util.URISupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DestinationView implements DestinationViewMBean {
private static final Logger LOG = LoggerFactory.getLogger(DestinationViewMBean.class);
protected final Destination destination;
protected final ManagedRegionBroker broker;
public DestinationView(ManagedRegionBroker broker, Destination destination) {
this.broker = broker;
this.destination = destination;
}
public void gc() {
destination.gc();
}
@Override
public String getName() {
return destination.getName();
}
@Override
public void resetStatistics() {
destination.getDestinationStatistics().reset();
}
@Override
public long getEnqueueCount() {
return destination.getDestinationStatistics().getEnqueues().getCount();
}
@Override
public long getDequeueCount() {
return destination.getDestinationStatistics().getDequeues().getCount();
}
@Override
public long getForwardCount() {
return destination.getDestinationStatistics().getForwards().getCount();
}
@Override
public long getDispatchCount() {
return destination.getDestinationStatistics().getDispatched().getCount();
}
@Override
public long getInFlightCount() {
return destination.getDestinationStatistics().getInflight().getCount();
}
@Override
public long getExpiredCount() {
return destination.getDestinationStatistics().getExpired().getCount();
}
@Override
public long getConsumerCount() {
return destination.getDestinationStatistics().getConsumers().getCount();
}
@Override
public long getQueueSize() {
return destination.getDestinationStatistics().getMessages().getCount();
}
@Override
public long getStoreMessageSize() {
MessageStore messageStore = destination.getMessageStore();
return messageStore != null ? messageStore.getMessageStoreStatistics().getMessageSize().getTotalSize() : 0;
}
public long getMessagesCached() {
return destination.getDestinationStatistics().getMessagesCached().getCount();
}
@Override
public int getMemoryPercentUsage() {
return destination.getMemoryUsage().getPercentUsage();
}
@Override
public long getMemoryUsageByteCount() {
return destination.getMemoryUsage().getUsage();
}
@Override
public long getMemoryLimit() {
return destination.getMemoryUsage().getLimit();
}
@Override
public void setMemoryLimit(long limit) {
destination.getMemoryUsage().setLimit(limit);
}
@Override
public double getAverageEnqueueTime() {
return destination.getDestinationStatistics().getProcessTime().getAverageTime();
}
@Override
public long getMaxEnqueueTime() {
return destination.getDestinationStatistics().getProcessTime().getMaxTime();
}
@Override
public long getMinEnqueueTime() {
return destination.getDestinationStatistics().getProcessTime().getMinTime();
}
/**
* @return the average size of a message (bytes)
*/
@Override
public long getAverageMessageSize() {
// we are okay with the size without decimals so cast to long
return (long) destination.getDestinationStatistics().getMessageSize().getAverageSize();
}
/**
* @return the max size of a message (bytes)
*/
@Override
public long getMaxMessageSize() {
return destination.getDestinationStatistics().getMessageSize().getMaxSize();
}
/**
* @return the min size of a message (bytes)
*/
@Override
public long getMinMessageSize() {
return destination.getDestinationStatistics().getMessageSize().getMinSize();
}
@Override
public boolean isPrioritizedMessages() {
return destination.isPrioritizedMessages();
}
@Override
public CompositeData[] browse() throws OpenDataException {
try {
return browse(null);
} catch (InvalidSelectorException e) {
// should not happen.
throw new RuntimeException(e);
}
}
@Override
public CompositeData[] browse(String selector) throws OpenDataException, InvalidSelectorException {
Message[] messages = destination.browse();
ArrayList<CompositeData> c = new ArrayList<CompositeData>();
MessageEvaluationContext ctx = new MessageEvaluationContext();
ctx.setDestination(destination.getActiveMQDestination());
BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector);
for (int i = 0; i < messages.length; i++) {
try {
if (selectorExpression == null) {
c.add(OpenTypeSupport.convert(messages[i]));
} else {
ctx.setMessageReference(messages[i]);
if (selectorExpression.matches(ctx)) {
c.add(OpenTypeSupport.convert(messages[i]));
}
}
} catch (Throwable e) {
LOG.warn("exception browsing destination", e);
}
}
CompositeData rc[] = new CompositeData[c.size()];
c.toArray(rc);
return rc;
}
/**
* Browses the current destination returning a list of messages
*/
@Override
public List<Object> browseMessages() throws InvalidSelectorException {
return browseMessages(null);
}
/**
* Browses the current destination with the given selector returning a list
* of messages
*/
@Override
public List<Object> browseMessages(String selector) throws InvalidSelectorException {
Message[] messages = destination.browse();
ArrayList<Object> answer = new ArrayList<Object>();
MessageEvaluationContext ctx = new MessageEvaluationContext();
ctx.setDestination(destination.getActiveMQDestination());
BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector);
for (int i = 0; i < messages.length; i++) {
try {
Message message = messages[i];
message.setReadOnlyBody(true);
if (selectorExpression == null) {
answer.add(message);
} else {
ctx.setMessageReference(message);
if (selectorExpression.matches(ctx)) {
answer.add(message);
}
}
} catch (Throwable e) {
LOG.warn("exception browsing destination", e);
}
}
return answer;
}
@Override
public TabularData browseAsTable() throws OpenDataException {
try {
return browseAsTable(null);
} catch (InvalidSelectorException e) {
throw new RuntimeException(e);
}
}
@Override
public TabularData browseAsTable(String selector) throws OpenDataException, InvalidSelectorException {
OpenTypeFactory factory = OpenTypeSupport.getFactory(ActiveMQMessage.class);
Message[] messages = destination.browse();
CompositeType ct = factory.getCompositeType();
TabularType tt = new TabularType("MessageList", "MessageList", ct, new String[] { "JMSMessageID" });
TabularDataSupport rc = new TabularDataSupport(tt);
MessageEvaluationContext ctx = new MessageEvaluationContext();
ctx.setDestination(destination.getActiveMQDestination());
BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector);
for (int i = 0; i < messages.length; i++) {
try {
if (selectorExpression == null) {
rc.put(new CompositeDataSupport(ct, factory.getFields(messages[i])));
} else {
ctx.setMessageReference(messages[i]);
if (selectorExpression.matches(ctx)) {
rc.put(new CompositeDataSupport(ct, factory.getFields(messages[i])));
}
}
} catch (Throwable e) {
LOG.warn("exception browsing destination", e);
}
}
return rc;
}
@Override
public String sendTextMessageWithProperties(String properties) throws Exception {
String[] kvs = properties.split(",");
Map<String, String> props = new HashMap<String, String>();
for (String kv : kvs) {
String[] it = kv.split("=");
if (it.length == 2) {
props.put(it[0],it[1]);
}
}
return sendTextMessage(props, props.remove("body"), props.remove("username"), props.remove("password"));
}
@Override
public String sendTextMessage(String body) throws Exception {
return sendTextMessage(Collections.EMPTY_MAP, body);
}
@Override
public String sendTextMessage(Map headers, String body) throws Exception {
return sendTextMessage(headers, body, null, null);
}
@Override
public String sendTextMessage(String body, String user, @Sensitive String password) throws Exception {
return sendTextMessage(Collections.EMPTY_MAP, body, user, password);
}
@Override
public String sendTextMessage(Map<String, String> headers, String body, String userName, @Sensitive String password) throws Exception {
String brokerUrl = "vm://" + broker.getBrokerName();
ActiveMQDestination dest = destination.getActiveMQDestination();
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(brokerUrl);
Connection connection = null;
try {
connection = cf.createConnection(userName, password);
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(dest);
ActiveMQTextMessage msg = (ActiveMQTextMessage) session.createTextMessage(body);
for (Iterator<Entry<String, String>> iter = headers.entrySet().iterator(); iter.hasNext();) {
Entry<String, String> entry = iter.next();
msg.setObjectProperty(entry.getKey(), entry.getValue());
}
producer.setDeliveryMode(msg.getJMSDeliveryMode());
producer.setPriority(msg.getPriority());
long ttl = 0;
if (msg.getExpiration() != 0) {
ttl = msg.getExpiration() - System.currentTimeMillis();
} else {
String timeToLive = headers.get("timeToLive");
if (timeToLive != null) {
ttl = Integer.valueOf(timeToLive);
}
}
producer.setTimeToLive(ttl > 0 ? ttl : 0);
producer.send(msg);
return msg.getJMSMessageID();
} finally {
if (connection != null) {
connection.close();
}
}
}
@Override
public int getMaxAuditDepth() {
return destination.getMaxAuditDepth();
}
@Override
public int getMaxProducersToAudit() {
return destination.getMaxProducersToAudit();
}
public boolean isEnableAudit() {
return destination.isEnableAudit();
}
public void setEnableAudit(boolean enableAudit) {
destination.setEnableAudit(enableAudit);
}
@Override
public void setMaxAuditDepth(int maxAuditDepth) {
destination.setMaxAuditDepth(maxAuditDepth);
}
@Override
public void setMaxProducersToAudit(int maxProducersToAudit) {
destination.setMaxProducersToAudit(maxProducersToAudit);
}
@Override
public float getMemoryUsagePortion() {
return destination.getMemoryUsage().getUsagePortion();
}
@Override
public long getProducerCount() {
return destination.getDestinationStatistics().getProducers().getCount();
}
@Override
public boolean isProducerFlowControl() {
return destination.isProducerFlowControl();
}
@Override
public void setMemoryUsagePortion(float value) {
destination.getMemoryUsage().setUsagePortion(value);
}
@Override
public void setProducerFlowControl(boolean producerFlowControl) {
destination.setProducerFlowControl(producerFlowControl);
}
@Override
public boolean isAlwaysRetroactive() {
return destination.isAlwaysRetroactive();
}
@Override
public void setAlwaysRetroactive(boolean alwaysRetroactive) {
destination.setAlwaysRetroactive(alwaysRetroactive);
}
/**
* Set's the interval at which warnings about producers being blocked by
* resource usage will be triggered. Values of 0 or less will disable
* warnings
*
* @param blockedProducerWarningInterval the interval at which warning about
* blocked producers will be triggered.
*/
@Override
public void setBlockedProducerWarningInterval(long blockedProducerWarningInterval) {
destination.setBlockedProducerWarningInterval(blockedProducerWarningInterval);
}
/**
*
* @return the interval at which warning about blocked producers will be
* triggered.
*/
@Override
public long getBlockedProducerWarningInterval() {
return destination.getBlockedProducerWarningInterval();
}
@Override
public int getMaxPageSize() {
return destination.getMaxPageSize();
}
@Override
public void setMaxPageSize(int pageSize) {
destination.setMaxPageSize(pageSize);
}
@Override
public boolean isUseCache() {
return destination.isUseCache();
}
@Override
public void setUseCache(boolean value) {
destination.setUseCache(value);
}
@Override
public ObjectName[] getSubscriptions() throws IOException, MalformedObjectNameException {
List<Subscription> subscriptions = destination.getConsumers();
ObjectName[] answer = new ObjectName[subscriptions.size()];
ObjectName brokerObjectName = broker.getBrokerService().getBrokerObjectName();
int index = 0;
for (Subscription subscription : subscriptions) {
String connectionClientId = subscription.getContext().getClientId();
answer[index++] = BrokerMBeanSupport.createSubscriptionName(brokerObjectName, connectionClientId, subscription.getConsumerInfo());
}
return answer;
}
@Override
public ObjectName getSlowConsumerStrategy() throws IOException, MalformedObjectNameException {
ObjectName result = null;
SlowConsumerStrategy strategy = destination.getSlowConsumerStrategy();
if (strategy != null && strategy instanceof AbortSlowConsumerStrategy) {
result = broker.registerSlowConsumerStrategy((AbortSlowConsumerStrategy)strategy);
}
return result;
}
@Override
public String getOptions() {
Map<String, String> options = destination.getActiveMQDestination().getOptions();
String optionsString = "";
try {
if (options != null) {
optionsString = URISupport.createQueryString(options);
}
} catch (URISyntaxException ignored) {}
return optionsString;
}
@Override
public boolean isDLQ() {
return destination.getActiveMQDestination().isDLQ();
}
@Override
public long getBlockedSends() {
return destination.getDestinationStatistics().getBlockedSends().getCount();
}
@Override
public double getAverageBlockedTime() {
return destination.getDestinationStatistics().getBlockedTime().getAverageTime();
}
@Override
public long getTotalBlockedTime() {
return destination.getDestinationStatistics().getBlockedTime().getTotalTime();
}
}