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.File;
020import java.util.ArrayList;
021import java.util.List;
022import java.util.Map;
023
024import javax.management.ObjectName;
025import javax.management.openmbean.CompositeDataSupport;
026import javax.management.openmbean.CompositeType;
027import javax.management.openmbean.TabularData;
028import javax.management.openmbean.TabularDataSupport;
029import javax.management.openmbean.TabularType;
030
031import org.apache.activemq.broker.BrokerService;
032import org.apache.activemq.broker.scheduler.JobSchedulerStore;
033import org.apache.activemq.store.PersistenceAdapter;
034import org.apache.activemq.usage.SystemUsage;
035
036public class HealthView implements HealthViewMBean {
037
038    ManagedRegionBroker broker;
039    String currentState = "Good";
040
041    public HealthView(ManagedRegionBroker broker) {
042        this.broker = broker;
043    }
044
045    @Override
046    public TabularData health() throws Exception {
047        OpenTypeSupport.OpenTypeFactory factory = OpenTypeSupport.getFactory(HealthStatus.class);
048        CompositeType ct = factory.getCompositeType();
049        TabularType tt = new TabularType("HealthStatus", "HealthStatus", ct, new String[] { "healthId", "level", "message", "resource" });
050        TabularDataSupport rc = new TabularDataSupport(tt);
051
052        List<HealthStatus> list = healthList();
053        for (HealthStatus healthStatus : list) {
054            rc.put(new CompositeDataSupport(ct, factory.getFields(healthStatus)));
055        }
056        return rc;
057    }
058
059    @Override
060    public List<HealthStatus> healthList() throws Exception {
061        List<HealthStatus> answer = new ArrayList<HealthStatus>();
062        Map<ObjectName, DestinationView> queueViews = broker.getQueueViews();
063        for (Map.Entry<ObjectName, DestinationView> entry : queueViews.entrySet()) {
064            DestinationView queue = entry.getValue();
065            if (queue.getConsumerCount() == 0 && queue.getProducerCount() > 0) {
066                ObjectName key = entry.getKey();
067                String message = "Queue " + queue.getName() + " has no consumers";
068                answer.add(new HealthStatus("org.apache.activemq.noConsumer", "WARNING", message, key.toString()));
069            }
070        }
071
072        /**
073         * Check persistence store directory limits
074         */
075        BrokerService brokerService = broker.getBrokerService();
076        if (brokerService != null && brokerService.getPersistenceAdapter() != null) {
077            PersistenceAdapter adapter = brokerService.getPersistenceAdapter();
078            File dir = adapter.getDirectory();
079            if (brokerService.isPersistent()) {
080                SystemUsage usage = brokerService.getSystemUsage();
081                if (dir != null && usage != null) {
082                    String dirPath = dir.getAbsolutePath();
083                    if (!dir.isAbsolute()) {
084                        dir = new File(dirPath);
085                    }
086
087                    while (dir != null && !dir.isDirectory()) {
088                        dir = dir.getParentFile();
089                    }
090                    long storeSize = adapter.size();
091                    long storeLimit = usage.getStoreUsage().getLimit();
092                    long dirFreeSpace = dir.getUsableSpace();
093
094                    if (storeSize != 0 && storeLimit != 0) {
095                        int val = (int) ((storeSize * 100) / storeLimit);
096                        if (val > 90) {
097                            answer.add(new HealthStatus("org.apache.activemq.StoreLimit", "WARNING", "Message Store size is within " + val + "% of its limit",
098                                adapter.toString()));
099                        }
100                    }
101
102                    if ((storeLimit - storeSize) > dirFreeSpace) {
103                        String message = "Store limit is " + storeLimit / (1024 * 1024) + " mb, whilst the data directory: " + dir.getAbsolutePath()
104                            + " only has " + dirFreeSpace / (1024 * 1024) + " mb of usable space";
105                        answer.add(new HealthStatus("org.apache.activemq.FreeDiskSpaceLeft", "WARNING", message, adapter.toString()));
106                    }
107                }
108
109                File tmpDir = brokerService.getTmpDataDirectory();
110                if (tmpDir != null) {
111
112                    String tmpDirPath = tmpDir.getAbsolutePath();
113                    if (!tmpDir.isAbsolute()) {
114                        tmpDir = new File(tmpDirPath);
115                    }
116
117                    long storeSize = usage.getTempUsage().getUsage();
118                    long storeLimit = usage.getTempUsage().getLimit();
119                    while (tmpDir != null && !tmpDir.isDirectory()) {
120                        tmpDir = tmpDir.getParentFile();
121                    }
122
123                    if (storeLimit != 0) {
124                        int val = (int) ((storeSize * 100) / storeLimit);
125                        if (val > 90) {
126                            answer.add(new HealthStatus("org.apache.activemq.TempStoreLimit", "WARNING", "TempMessage Store size is within " + val
127                                + "% of its limit", adapter.toString()));
128                        }
129                    }
130                }
131            }
132        }
133
134        if (brokerService != null && brokerService.getJobSchedulerStore() != null) {
135            JobSchedulerStore scheduler = brokerService.getJobSchedulerStore();
136            File dir = scheduler.getDirectory();
137            if (brokerService.isPersistent()) {
138                SystemUsage usage = brokerService.getSystemUsage();
139                if (dir != null && usage != null) {
140                    String dirPath = dir.getAbsolutePath();
141                    if (!dir.isAbsolute()) {
142                        dir = new File(dirPath);
143                    }
144
145                    while (dir != null && !dir.isDirectory()) {
146                        dir = dir.getParentFile();
147                    }
148                    long storeSize = scheduler.size();
149                    long storeLimit = usage.getJobSchedulerUsage().getLimit();
150                    long dirFreeSpace = dir.getUsableSpace();
151
152                    if (storeSize != 0 && storeLimit != 0) {
153                        int val = (int) ((storeSize * 100) / storeLimit);
154                        if (val > 90) {
155                            answer.add(new HealthStatus("org.apache.activemq.JobSchedulerLimit", "WARNING", "JobSchedulerMessage Store size is within " + val
156                                + "% of its limit", scheduler.toString()));
157                        }
158                    }
159
160                    if ((storeLimit - storeSize) > dirFreeSpace) {
161                        String message = "JobSchedulerStore limit is " + storeLimit / (1024 * 1024) + " mb, whilst the data directory: "
162                            + dir.getAbsolutePath() + " only has " + dirFreeSpace / (1024 * 1024) + " mb of usable space";
163                        answer.add(new HealthStatus("org.apache.activemq.FreeDiskSpaceLeft", "WARNING", message, scheduler.toString()));
164                    }
165                }
166            }
167        }
168
169        if (answer != null && !answer.isEmpty()) {
170            this.currentState = "Getting Worried {";
171            for (HealthStatus hs : answer) {
172                currentState += hs + " , ";
173            }
174            currentState += " }";
175        } else {
176            this.currentState = "Good";
177        }
178        return answer;
179    }
180
181    /**
182     * @return String representation of the current Broker state
183     */
184    @Override
185    public String getCurrentStatus() {
186        return this.currentState;
187    }
188}