001/*
002 *  Copyright 2015 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.runtime.plugins.admin.jvmstatus;
017
018import java.io.File;
019import java.io.IOException;
020import java.lang.management.ManagementFactory;
021import java.lang.management.MemoryMXBean;
022import java.lang.management.RuntimeMXBean;
023import java.lang.management.ThreadMXBean;
024import java.util.ArrayList;
025import java.util.Collections;
026import java.util.Date;
027import java.util.HashMap;
028import java.util.HashSet;
029import java.util.List;
030import java.util.Map;
031import java.util.Set;
032
033import org.apache.avalon.framework.activity.Initializable;
034import org.apache.avalon.framework.component.Component;
035import org.apache.avalon.framework.logger.AbstractLogEnabled;
036import org.apache.avalon.framework.service.ServiceException;
037import org.apache.avalon.framework.service.ServiceManager;
038import org.apache.avalon.framework.service.Serviceable;
039import org.apache.commons.io.FileUtils;
040import org.rrd4j.core.Archive;
041import org.rrd4j.core.RrdDb;
042
043import org.ametys.core.ui.Callable;
044import org.ametys.core.util.DateUtils;
045import org.ametys.core.util.I18nUtils;
046import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.MonitoringConstants;
047import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.MonitoringExtensionPoint;
048import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.SampleManager;
049import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.alerts.AlertSampleManager;
050import org.ametys.runtime.plugins.admin.jvmstatus.monitoring.alerts.AlertSampleManager.Threshold;
051import org.ametys.runtime.servlet.RuntimeConfig;
052
053/**
054 * This helper allow to get information or runs some operations on JVM system
055 */
056public class JVMStatusHelper extends AbstractLogEnabled implements Component, Serviceable, Initializable, MonitoringConstants
057{
058    /** The monitoring extension point */
059    private MonitoringExtensionPoint _monitoringExtensionPoint;
060    
061    /** Component containing i18n utilitary methods */
062    private I18nUtils _i18nUtils;
063
064    private String _rrdStoragePath;
065    
066    @Override
067    public void service(ServiceManager manager) throws ServiceException
068    {
069        _monitoringExtensionPoint = (MonitoringExtensionPoint) manager.lookup(MonitoringExtensionPoint.ROLE);
070        _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
071    }
072    
073    public void initialize() throws Exception
074    {
075        _rrdStoragePath = FileUtils.getFile(RuntimeConfig.getInstance().getAmetysHome(), RRD_STORAGE_DIRECTORY).getPath();
076    }
077    
078    /**
079     * Runs a garbage collector.
080     * @return an empty map
081     */
082    @Callable
083    public Map<String, Object> garbageCollect ()
084    {
085        if (getLogger().isInfoEnabled())
086        {
087            getLogger().info("Administrator is garbage collecting");
088        }
089        
090        System.gc();
091        
092        return Collections.EMPTY_MAP;
093    }
094    
095    /**
096     * Retrieves information about the general status of the system 
097     * @return a map containing the general status information
098     */
099    @Callable
100    public Map<String, Object> getGeneralStatus()
101    {
102        Map<String, Object> result = new HashMap<>();
103        
104        result.put("osTime", DateUtils.dateToString(new Date()));
105        try
106        {
107            result.put("activeSessions", SessionCountListener.getSessionCount());
108        }
109        catch (IllegalStateException e)
110        {
111            // empty : no value in activeSession means an error
112        }
113        
114        try
115        {
116            result.put("activeRequests", RequestCountListener.getCurrentRequestCount());
117        }
118        catch (IllegalStateException e)
119        {
120            // empty : no value in activeSession means an error
121        }
122        
123        
124        ThreadMXBean tBean = ManagementFactory.getThreadMXBean();
125        MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
126        RuntimeMXBean rBean = ManagementFactory.getRuntimeMXBean();
127        
128        result.put("activeThreads", tBean.getThreadCount());
129        long[] lockedThreads = ManagementFactory.getThreadMXBean().findMonitorDeadlockedThreads();
130        
131        result.put("deadlockThreads", lockedThreads != null ? String.valueOf(lockedThreads.length) : "0");
132    
133        result.put("heap-memory-max", mBean.getHeapMemoryUsage().getMax());
134        result.put("heap-memory-used", mBean.getHeapMemoryUsage().getUsed());
135        result.put("heap-memory-commited", mBean.getHeapMemoryUsage().getCommitted());
136        
137
138        result.put("startTime", DateUtils.dateToString(new Date(rBean.getStartTime())));
139        
140        return result;
141    }
142    
143    /**
144     * Retrieves the monitoring data 
145     * @return a map containing the monitoring data
146     */
147    @Callable
148    public Map<String, Object> getMonitoringData()
149    {
150        Map<String, Object> result = new HashMap<> ();
151        
152        Map<String, Object> samples = new HashMap<> ();
153        List<String> periods = new ArrayList<> ();
154        
155        for (Period period : Period.values())
156        {
157            periods.add(period.toString());
158        }
159        
160        samples.put("periods", periods);
161        
162        List<Map<String, Object>> sampleList = new ArrayList<> ();
163        for (String extensionId : _monitoringExtensionPoint.getExtensionsIds())
164        {
165            Map<String, Object> sample = new HashMap<> ();
166            SampleManager sampleManager = _monitoringExtensionPoint.getExtension(extensionId);
167
168            sample.put("id", sampleManager.getId());
169            sample.put("label", _i18nUtils.translate(sampleManager.getLabel()));
170            sample.put("description", _i18nUtils.translate(sampleManager.getDescription()));
171            if (sampleManager instanceof AlertSampleManager)
172            {
173                Map<String, Object> thresholdValues = new HashMap<>(); 
174                
175                Map<String, Threshold> thresholds = ((AlertSampleManager) sampleManager).getThresholdValues();
176                for (String datasourceName : thresholds.keySet())
177                {
178                    thresholdValues.put(datasourceName, thresholds.get(datasourceName).getValue());
179                }
180                
181                sample.put("thresholds", thresholdValues);
182            }
183
184            File rrdFile = new File(_rrdStoragePath, sampleManager.getId() + RRD_EXT);
185            if (getLogger().isDebugEnabled())
186            {
187                getLogger().debug("Using RRD file: " + rrdFile);
188            }
189            
190            RrdDb rrdDb = null;
191            try
192            {
193                rrdDb = new RrdDb(rrdFile.getPath());
194                
195                sample.put("ds", rrdDb.getDsNames());
196                
197                Set<String> consolidationFunction = new HashSet<>();
198                for (int i = 0; i < rrdDb.getArcCount(); i++)
199                {
200                    Archive archive = rrdDb.getArchive(i);
201                    consolidationFunction.add(archive.getConsolFun().toString());
202                }
203                sample.put("consolFun", consolidationFunction);
204            }
205            catch (Exception e)
206            {
207                getLogger().error("Unable to collect sample for: " + sampleManager.getId(), e);
208            }
209            finally
210            {
211                if (rrdDb != null)
212                {
213                    try
214                    {
215                        rrdDb.close();
216                    }
217                    catch (IOException e)
218                    {
219                        getLogger().warn("Unable to close RRD file: " + rrdFile, e);
220                    }
221                }
222            }
223            
224            sampleList.add(sample);
225        }
226        
227        samples.put("sampleList", sampleList);
228        result.put("samples", samples);
229        return result;
230    }
231}