001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.broker.jmx;
018
019import java.io.IOException;
020import java.net.URISyntaxException;
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.HashMap;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Map;
027import java.util.Map.Entry;
028
029import javax.jms.Connection;
030import javax.jms.InvalidSelectorException;
031import javax.jms.MessageProducer;
032import javax.jms.Session;
033import javax.management.MalformedObjectNameException;
034import javax.management.ObjectName;
035import javax.management.openmbean.CompositeData;
036import javax.management.openmbean.CompositeDataSupport;
037import javax.management.openmbean.CompositeType;
038import javax.management.openmbean.OpenDataException;
039import javax.management.openmbean.TabularData;
040import javax.management.openmbean.TabularDataSupport;
041import javax.management.openmbean.TabularType;
042
043import org.apache.activemq.ActiveMQConnectionFactory;
044import org.apache.activemq.broker.jmx.OpenTypeSupport.OpenTypeFactory;
045import org.apache.activemq.broker.region.Destination;
046import org.apache.activemq.broker.region.Subscription;
047import org.apache.activemq.broker.region.policy.AbortSlowConsumerStrategy;
048import org.apache.activemq.broker.region.policy.SlowConsumerStrategy;
049import org.apache.activemq.command.ActiveMQDestination;
050import org.apache.activemq.command.ActiveMQMessage;
051import org.apache.activemq.command.ActiveMQTextMessage;
052import org.apache.activemq.command.Message;
053import org.apache.activemq.filter.BooleanExpression;
054import org.apache.activemq.filter.NonCachedMessageEvaluationContext;
055import org.apache.activemq.selector.SelectorParser;
056import org.apache.activemq.store.MessageStore;
057import org.apache.activemq.util.URISupport;
058import org.slf4j.Logger;
059import org.slf4j.LoggerFactory;
060
061public class DestinationView implements DestinationViewMBean {
062    private static final Logger LOG = LoggerFactory.getLogger(DestinationViewMBean.class);
063    protected final Destination destination;
064    protected final ManagedRegionBroker broker;
065
066    public DestinationView(ManagedRegionBroker broker, Destination destination) {
067        this.broker = broker;
068        this.destination = destination;
069    }
070
071    public void gc() {
072        destination.gc();
073    }
074
075    @Override
076    public String getName() {
077        return destination.getName();
078    }
079
080    @Override
081    public void resetStatistics() {
082        destination.getDestinationStatistics().reset();
083    }
084
085    @Override
086    public long getEnqueueCount() {
087        return destination.getDestinationStatistics().getEnqueues().getCount();
088    }
089
090    @Override
091    public long getDequeueCount() {
092        return destination.getDestinationStatistics().getDequeues().getCount();
093    }
094
095    @Override
096    public long getForwardCount() {
097        return destination.getDestinationStatistics().getForwards().getCount();
098    }
099
100    @Override
101    public long getDispatchCount() {
102        return destination.getDestinationStatistics().getDispatched().getCount();
103    }
104
105    @Override
106    public long getInFlightCount() {
107        return destination.getDestinationStatistics().getInflight().getCount();
108    }
109
110    @Override
111    public long getExpiredCount() {
112        return destination.getDestinationStatistics().getExpired().getCount();
113    }
114
115    @Override
116    public long getConsumerCount() {
117        return destination.getDestinationStatistics().getConsumers().getCount();
118    }
119
120    @Override
121    public long getQueueSize() {
122        return destination.getDestinationStatistics().getMessages().getCount();
123    }
124
125    @Override
126    public long getStoreMessageSize() {
127        MessageStore messageStore = destination.getMessageStore();
128        return messageStore != null ? messageStore.getMessageStoreStatistics().getMessageSize().getTotalSize() : 0;
129    }
130
131    public long getMessagesCached() {
132        return destination.getDestinationStatistics().getMessagesCached().getCount();
133    }
134
135    @Override
136    public int getMemoryPercentUsage() {
137        return destination.getMemoryUsage().getPercentUsage();
138    }
139
140    @Override
141    public long getMemoryUsageByteCount() {
142        return destination.getMemoryUsage().getUsage();
143    }
144
145    @Override
146    public long getMemoryLimit() {
147        return destination.getMemoryUsage().getLimit();
148    }
149
150    @Override
151    public void setMemoryLimit(long limit) {
152        destination.getMemoryUsage().setLimit(limit);
153    }
154
155    @Override
156    public double getAverageEnqueueTime() {
157        return destination.getDestinationStatistics().getProcessTime().getAverageTime();
158    }
159
160    @Override
161    public int getTempUsagePercentUsage() {
162        return destination.getTempUsage().getPercentUsage();
163    }
164
165    @Override
166    public long getTempUsageLimit() {
167        return destination.getTempUsage().getLimit();
168    }
169
170    @Override
171    public void setTempUsageLimit(long limit) {
172        destination.getTempUsage().setLimit(limit);
173    }
174
175    @Override
176    public long getMaxEnqueueTime() {
177        return destination.getDestinationStatistics().getProcessTime().getMaxTime();
178    }
179
180    @Override
181    public long getMinEnqueueTime() {
182        return destination.getDestinationStatistics().getProcessTime().getMinTime();
183    }
184
185    /**
186     * @return the average size of a message (bytes)
187     */
188    @Override
189    public long getAverageMessageSize() {
190        // we are okay with the size without decimals so cast to long
191        return (long) destination.getDestinationStatistics().getMessageSize().getAverageSize();
192    }
193
194    /**
195     * @return the max size of a message (bytes)
196     */
197    @Override
198    public long getMaxMessageSize() {
199        return destination.getDestinationStatistics().getMessageSize().getMaxSize();
200    }
201
202    /**
203     * @return the min size of a message (bytes)
204     */
205    @Override
206    public long getMinMessageSize() {
207        return destination.getDestinationStatistics().getMessageSize().getMinSize();
208    }
209
210
211    @Override
212    public boolean isPrioritizedMessages() {
213        return destination.isPrioritizedMessages();
214    }
215
216    @Override
217    public CompositeData[] browse() throws OpenDataException {
218        try {
219            return browse(null);
220        } catch (InvalidSelectorException e) {
221            // should not happen.
222            throw new RuntimeException(e);
223        }
224    }
225
226    @Override
227    public CompositeData[] browse(String selector) throws OpenDataException, InvalidSelectorException {
228        Message[] messages = destination.browse();
229        ArrayList<CompositeData> c = new ArrayList<CompositeData>();
230
231        NonCachedMessageEvaluationContext ctx = new NonCachedMessageEvaluationContext();
232        ctx.setDestination(destination.getActiveMQDestination());
233        BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector);
234
235        for (int i = 0; i < messages.length; i++) {
236            try {
237
238                if (selectorExpression == null) {
239                    c.add(OpenTypeSupport.convert(messages[i]));
240                } else {
241                    ctx.setMessageReference(messages[i]);
242                    if (selectorExpression.matches(ctx)) {
243                        c.add(OpenTypeSupport.convert(messages[i]));
244                    }
245                }
246
247            } catch (Throwable e) {
248                LOG.warn("exception browsing destination", e);
249            }
250        }
251
252        CompositeData rc[] = new CompositeData[c.size()];
253        c.toArray(rc);
254        return rc;
255    }
256
257    /**
258     * Browses the current destination returning a list of messages
259     */
260    @Override
261    public List<Object> browseMessages() throws InvalidSelectorException {
262        return browseMessages(null);
263    }
264
265    /**
266     * Browses the current destination with the given selector returning a list
267     * of messages
268     */
269    @Override
270    public List<Object> browseMessages(String selector) throws InvalidSelectorException {
271        Message[] messages = destination.browse();
272        ArrayList<Object> answer = new ArrayList<Object>();
273
274        NonCachedMessageEvaluationContext ctx = new NonCachedMessageEvaluationContext();
275        ctx.setDestination(destination.getActiveMQDestination());
276        BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector);
277
278        for (int i = 0; i < messages.length; i++) {
279            try {
280                Message message = messages[i];
281                message.setReadOnlyBody(true);
282                if (selectorExpression == null) {
283                    answer.add(message);
284                } else {
285                    ctx.setMessageReference(message);
286                    if (selectorExpression.matches(ctx)) {
287                        answer.add(message);
288                    }
289                }
290
291            } catch (Throwable e) {
292                LOG.warn("exception browsing destination", e);
293            }
294        }
295        return answer;
296    }
297
298    @Override
299    public TabularData browseAsTable() throws OpenDataException {
300        try {
301            return browseAsTable(null);
302        } catch (InvalidSelectorException e) {
303            throw new RuntimeException(e);
304        }
305    }
306
307    @Override
308    public TabularData browseAsTable(String selector) throws OpenDataException, InvalidSelectorException {
309        OpenTypeFactory factory = OpenTypeSupport.getFactory(ActiveMQMessage.class);
310        Message[] messages = destination.browse();
311        CompositeType ct = factory.getCompositeType();
312        TabularType tt = new TabularType("MessageList", "MessageList", ct, new String[] { "JMSMessageID" });
313        TabularDataSupport rc = new TabularDataSupport(tt);
314
315        NonCachedMessageEvaluationContext ctx = new NonCachedMessageEvaluationContext();
316        ctx.setDestination(destination.getActiveMQDestination());
317        BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector);
318
319        for (int i = 0; i < messages.length; i++) {
320            try {
321                if (selectorExpression == null) {
322                    rc.put(new CompositeDataSupport(ct, factory.getFields(messages[i])));
323                } else {
324                    ctx.setMessageReference(messages[i]);
325                    if (selectorExpression.matches(ctx)) {
326                        rc.put(new CompositeDataSupport(ct, factory.getFields(messages[i])));
327                    }
328                }
329            } catch (Throwable e) {
330                LOG.warn("exception browsing destination", e);
331            }
332        }
333
334        return rc;
335    }
336
337    @Override
338    public String sendTextMessageWithProperties(String properties) throws Exception {
339        String[] kvs = properties.split(",");
340        Map<String, String> props = new HashMap<String, String>();
341        for (String kv : kvs) {
342            String[] it = kv.split("=");
343            if (it.length == 2) {
344                props.put(it[0],it[1]);
345            }
346        }
347        return sendTextMessage(props, props.remove("body"), props.remove("username"), props.remove("password"));
348    }
349
350    @Override
351    public String sendTextMessage(String body) throws Exception {
352        return sendTextMessage(Collections.EMPTY_MAP, body);
353    }
354
355    @Override
356    public String sendTextMessage(Map headers, String body) throws Exception {
357        return sendTextMessage(headers, body, null, null);
358    }
359
360    @Override
361    public String sendTextMessage(String body, String user, @Sensitive String password) throws Exception {
362        return sendTextMessage(Collections.EMPTY_MAP, body, user, password);
363    }
364
365    @Override
366    public String sendTextMessage(Map<String, String> headers, String body, String userName, @Sensitive String password) throws Exception {
367
368        String brokerUrl = "vm://" + broker.getBrokerName();
369        ActiveMQDestination dest = destination.getActiveMQDestination();
370
371        ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(brokerUrl);
372        Connection connection = null;
373        try {
374            connection = cf.createConnection(userName, password);
375            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
376            MessageProducer producer = session.createProducer(dest);
377            ActiveMQTextMessage msg = (ActiveMQTextMessage) session.createTextMessage(body);
378
379            for (Iterator<Entry<String, String>> iter = headers.entrySet().iterator(); iter.hasNext();) {
380                Entry<String, String> entry = iter.next();
381                msg.setObjectProperty(entry.getKey(), entry.getValue());
382            }
383
384            producer.setDeliveryMode(msg.getJMSDeliveryMode());
385            producer.setPriority(msg.getPriority());
386            long ttl = 0;
387            if (msg.getExpiration() != 0) {
388                ttl = msg.getExpiration() - System.currentTimeMillis();
389            } else {
390                String timeToLive = headers.get("timeToLive");
391                if (timeToLive != null) {
392                    ttl = Integer.valueOf(timeToLive);
393                }
394            }
395            producer.setTimeToLive(ttl > 0 ? ttl : 0);
396            producer.send(msg);
397
398            return msg.getJMSMessageID();
399
400        } finally {
401            if (connection != null) {
402                connection.close();
403            }
404        }
405    }
406
407    @Override
408    public int getMaxAuditDepth() {
409        return destination.getMaxAuditDepth();
410    }
411
412    @Override
413    public int getMaxProducersToAudit() {
414        return destination.getMaxProducersToAudit();
415    }
416
417    public boolean isEnableAudit() {
418        return destination.isEnableAudit();
419    }
420
421    public void setEnableAudit(boolean enableAudit) {
422        destination.setEnableAudit(enableAudit);
423    }
424
425    @Override
426    public void setMaxAuditDepth(int maxAuditDepth) {
427        destination.setMaxAuditDepth(maxAuditDepth);
428    }
429
430    @Override
431    public void setMaxProducersToAudit(int maxProducersToAudit) {
432        destination.setMaxProducersToAudit(maxProducersToAudit);
433    }
434
435    @Override
436    public float getMemoryUsagePortion() {
437        return destination.getMemoryUsage().getUsagePortion();
438    }
439
440    @Override
441    public long getProducerCount() {
442        return destination.getDestinationStatistics().getProducers().getCount();
443    }
444
445    @Override
446    public boolean isProducerFlowControl() {
447        return destination.isProducerFlowControl();
448    }
449
450    @Override
451    public void setMemoryUsagePortion(float value) {
452        destination.getMemoryUsage().setUsagePortion(value);
453    }
454
455    @Override
456    public void setProducerFlowControl(boolean producerFlowControl) {
457        destination.setProducerFlowControl(producerFlowControl);
458    }
459
460    @Override
461    public boolean isAlwaysRetroactive() {
462        return destination.isAlwaysRetroactive();
463    }
464
465    @Override
466    public void setAlwaysRetroactive(boolean alwaysRetroactive) {
467        destination.setAlwaysRetroactive(alwaysRetroactive);
468    }
469
470    /**
471     * Set's the interval at which warnings about producers being blocked by
472     * resource usage will be triggered. Values of 0 or less will disable
473     * warnings
474     *
475     * @param blockedProducerWarningInterval the interval at which warning about
476     *            blocked producers will be triggered.
477     */
478    @Override
479    public void setBlockedProducerWarningInterval(long blockedProducerWarningInterval) {
480        destination.setBlockedProducerWarningInterval(blockedProducerWarningInterval);
481    }
482
483    /**
484     *
485     * @return the interval at which warning about blocked producers will be
486     *         triggered.
487     */
488    @Override
489    public long getBlockedProducerWarningInterval() {
490        return destination.getBlockedProducerWarningInterval();
491    }
492
493    @Override
494    public int getMaxPageSize() {
495        return destination.getMaxPageSize();
496    }
497
498    @Override
499    public void setMaxPageSize(int pageSize) {
500        destination.setMaxPageSize(pageSize);
501    }
502
503    @Override
504    public boolean isUseCache() {
505        return destination.isUseCache();
506    }
507
508    @Override
509    public void setUseCache(boolean value) {
510        destination.setUseCache(value);
511    }
512
513    @Override
514    public ObjectName[] getSubscriptions() throws IOException, MalformedObjectNameException {
515        List<Subscription> subscriptions = destination.getConsumers();
516        ObjectName[] answer = new ObjectName[subscriptions.size()];
517        ObjectName brokerObjectName = broker.getBrokerService().getBrokerObjectName();
518        int index = 0;
519        for (Subscription subscription : subscriptions) {
520            String connectionClientId = subscription.getContext().getClientId();
521            answer[index++] = BrokerMBeanSupport.createSubscriptionName(brokerObjectName, connectionClientId, subscription.getConsumerInfo());
522        }
523        return answer;
524    }
525
526    @Override
527    public ObjectName getSlowConsumerStrategy() throws IOException, MalformedObjectNameException {
528        ObjectName result = null;
529        SlowConsumerStrategy strategy = destination.getSlowConsumerStrategy();
530        if (strategy != null && strategy instanceof AbortSlowConsumerStrategy) {
531            result = broker.registerSlowConsumerStrategy((AbortSlowConsumerStrategy)strategy);
532        }
533        return result;
534    }
535
536    @Override
537    public String getOptions() {
538        Map<String, String> options = destination.getActiveMQDestination().getOptions();
539        String optionsString = "";
540        try {
541            if (options != null) {
542                optionsString = URISupport.createQueryString(options);
543            }
544        } catch (URISyntaxException ignored) {}
545        return optionsString;
546    }
547
548    @Override
549    public boolean isDLQ() {
550        return destination.getActiveMQDestination().isDLQ();
551    }
552
553    @Override
554    public void setDLQ(boolean val) {
555         destination.getActiveMQDestination().setDLQ(val);
556    }
557
558    @Override
559    public long getBlockedSends() {
560        return destination.getDestinationStatistics().getBlockedSends().getCount();
561    }
562
563    @Override
564    public double getAverageBlockedTime() {
565        return destination.getDestinationStatistics().getBlockedTime().getAverageTime();
566    }
567
568    @Override
569    public long getTotalBlockedTime() {
570        return destination.getDestinationStatistics().getBlockedTime().getTotalTime();
571    }
572
573}