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     */
017    package org.apache.geronimo.monitoring.snapshot;
018    
019    import java.io.File;
020    import java.lang.reflect.UndeclaredThrowableException;
021    import java.util.ArrayList;
022    import java.util.HashMap;
023    import java.util.Iterator;
024    import java.util.Properties;
025    import java.util.Set;
026    
027    import javax.management.ObjectName;
028    import javax.naming.Context;
029    import javax.naming.InitialContext;
030    
031    import org.apache.commons.logging.Log;
032    import org.apache.commons.logging.LogFactory;
033    import org.apache.geronimo.monitoring.MBeanHelper;
034    import org.apache.geronimo.monitoring.MasterRemoteControlLocal;
035    
036    /**
037     * Thread that is in charge of executing every x milliseconds. Upon each
038     * iteration, a snapshot of the server's information is recorded.
039     */
040    public class SnapshotProcessor {
041        
042        private static Log log = LogFactory.getLog(SnapshotProcessor.class);
043        
044        /**
045         * Collects JSR-77 statistics for all mbeans that have been chosen to 
046         * be monitored and stores it in a DB. Will also, archive snapshots
047         * if they have passed their retention period.
048         * @param username
049         * @param password
050         */
051        public static void takeSnapshot(String username, String password) {
052            // ensure that there is a 'monitoring' directory
053            ensureMonitorDir();
054            // get any saved mbean names from snapshot-config.xml
055            ArrayList<String> mbeanNames = SnapshotConfigXMLBuilder.getMBeanNames();
056            // get a handle on the mrc
057            MasterRemoteControlLocal mrc = getMRC(username, password);
058            // in the case where nothing is present, grab a set of default mbeans
059            if(mbeanNames.size() <= 0) {
060                mbeanNames = getDefaultMBeanList(mrc);
061            }
062            // turn on all stats in the list
063            setStatsOn(mbeanNames, mrc);
064            try {
065                // take a snapshot
066                log.info("======SNAPSHOT======");
067                // instantiate map <mbean name, stats for mbean>
068                HashMap<String, HashMap<String, Long>> aggregateStats = new HashMap<String, HashMap<String, Long>>();
069                // for each mbean name in the list, get its stats
070                for(int i = 0; i < mbeanNames.size(); i++) {
071                    String mbeanName = mbeanNames.get(i);
072                    HashMap<String, Long> stats = (HashMap<String, Long>)mrc.getStats(mbeanName);
073                    aggregateStats.put(mbeanName, stats);
074                }
075                
076                // store the data in a DB
077                (new SnapshotDBHelper()).addSnapshotToDB(aggregateStats);
078                
079                for(Iterator itt = aggregateStats.keySet().iterator(); itt.hasNext(); ) {
080                    String mbean = (String)itt.next();
081                    HashMap<String, Long> stats = aggregateStats.get(mbean);
082                    log.info(mbean);
083                    for(Iterator it = stats.keySet().iterator(); it.hasNext(); ) {
084                        String key = (String)it.next();
085                        Long value = (Long)stats.get(key);
086                        log.info(key + ": " + value);
087                    }
088                }
089            } catch(Exception e) {
090                log.error(e.getMessage(), e);
091            }
092        }
093        
094        /**
095         * Turns all statistics on for each mbean in the list.
096         * 
097         * @param mbeanList
098         */
099        private static void setStatsOn(ArrayList<String> mbeanList, MasterRemoteControlLocal mrc) {
100            // for each mbean name in the list
101            for(int i = 0; i < mbeanList.size(); i++) {
102                // turn the statistics collection on
103                String methodName = "setStatsOn";
104                Object[] params = new Object[] { Boolean.TRUE };
105                String[] signatures = new String[] { "boolean" };
106                try {
107                    ObjectName objName = new ObjectName(mbeanList.get(i));
108                    mrc.invoke(objName, methodName, params, signatures);
109                    log.info("Stats for " + mbeanList.get(i) + " was turned on.");
110                }catch (UndeclaredThrowableException e) {
111                    // HACK : this will happen for components that always collect statistics
112                    // and do not have StatsOn method.
113                } catch(Exception e) { 
114                    log.error(e.getMessage(), e);
115                }
116            }
117        }
118    
119        /**
120         * @return A list of all default mbeans; namely, all connector or container mbean names
121         * Prereq: in order to be a connector or container mbean the name must contain "Connector"/"Container" 
122         * and "Tomcat"/"Jetty" or JVM.
123         */
124        private static ArrayList<String> getDefaultMBeanList(MasterRemoteControlLocal mrc) {
125            Set<String> mbeans = MBeanHelper.getStatsProvidersMBeans( mrc.getAllMBeanNames() );
126            ArrayList<String> retval = new ArrayList<String>();
127            for(Iterator it = mbeans.iterator(); it.hasNext(); ) {
128                String name = (String)it.next();
129                if(((name.contains("Connector") || name.contains("Container")) && (name.contains("Jetty") || name.contains("Tomcat")))
130                                    || name.contains("JVM")) {
131                    // this is a connector or JVM, so add to the list
132                    retval.add(name);
133                    // update the snapshot-config.xml to include these
134                    SnapshotConfigXMLBuilder.addMBeanName(name);
135                }
136            }
137            return retval;
138        }
139        
140        /**
141         * Checks to see if the GERONIMO_HOME/var/monitoring/ directory was made.
142         * If not, the method creates it.
143         */
144        public static void ensureMonitorDir() {
145            final String pathToDir = 
146                System.getProperty("org.apache.geronimo.home.dir") + "/var/monitoring/";
147            File dir = new File(pathToDir);
148            if(dir.exists() && dir.isDirectory()) {
149                // all good
150                return;
151            } else {
152                // make a directory
153                if(dir.mkdir()) {
154                    // directory was successfully created
155                    log.info("/var/monitoring directory created.");
156                    return;
157                } else {
158                    log.error("Could not make the directory " + pathToDir);
159                }
160            }
161        }
162        
163        /**
164         * @return An instance of a MRC. 
165         */
166        public static MasterRemoteControlLocal getMRC(String username, String password) {
167            Properties props = new Properties();
168            props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
169            props.setProperty(Context.SECURITY_PRINCIPAL, username);
170            props.setProperty(Context.SECURITY_CREDENTIALS, password);
171            props.setProperty("openejb.authentication.realmName", "geronimo-admin");
172            try {
173                Context ic = new InitialContext(props);
174                MasterRemoteControlLocal mrc = (MasterRemoteControlLocal)ic.lookup("ejb/mgmt/MRCLocal");
175                return mrc;
176            } catch(Exception e) {
177                return null;
178            }
179        }
180    }