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.system.main;
018    
019    import java.io.PrintStream;
020    
021    import org.apache.geronimo.kernel.Kernel;
022    import org.apache.geronimo.kernel.repository.Artifact;
023    import java.text.DateFormat;
024    import java.text.SimpleDateFormat;
025    import java.util.TimeZone;
026    import java.util.Date;
027    
028    /**
029     * A startup monitor that shows the progress of loading and starting
030     * modules, outputing a new line for each module started
031     * showing the time taken to start the module along with the
032     * moduleId.
033     * <p/>
034     * This startup monitor produces more lines of output than the
035     * ProgressBarStartupMonitor but its output is suitable for redirection
036     * to a file or for when Geronimo is running under an IDE or other tool.
037     * <p/>
038     * A summary will also be produced containing a list of ports
039     * Geronimo is listening on, the configIds of application modules
040     * that were started and the URLs of Web applications that were started.
041     *
042     * @version $Revision: 1.0$
043     */
044    public class LongStartupMonitor implements StartupMonitor {
045    
046        /**
047         * PrintStream
048         */
049        private PrintStream out;
050    
051        /**
052         * Number of modules to start
053         */
054        private int numModules;
055    
056        /**
057         * Number of digits in number of modules to start
058         */
059        private int numModulesDigits;
060    
061        /**
062         * Number of modules currently being started
063         */
064        private int moduleNum;
065    
066        /**
067         * Length of longest module name
068         */
069        private int longestModuleNameLength;
070        
071        /**
072         * Time Geronimo was started
073         */
074        private long started;
075    
076        /**
077         * Time the current module being processed was started
078         */
079        private long moduleStarted;
080    
081        /**
082         * The Kernel of the system being started
083         */
084        private Kernel kernel;
085    
086        public synchronized void systemStarting(long startTime) {
087            out = System.out;
088            started = startTime;
089        }
090    
091        public synchronized void systemStarted(Kernel kernel) {
092            this.kernel = kernel;
093        }
094    
095        public synchronized void foundModules(Artifact[] modules) {
096            numModules = modules.length;
097            numModulesDigits = Integer.toString(numModules).length();
098            
099            for (int i = 0, len= 0; i < modules.length; i++) {
100                len = modules[i].toString().length();
101                if (len > longestModuleNameLength)
102                    longestModuleNameLength = len;
103            }
104        }
105    
106        public synchronized void moduleLoading(Artifact module) {
107            StringBuffer buf = new StringBuffer("Module ");
108            // pad module index
109            int configIndexDigits = Integer.toString(++moduleNum).length();
110            for (; configIndexDigits < numModulesDigits; configIndexDigits++) {
111                buf.append(' ');
112            }
113            // append module index / total configs
114            buf.append(moduleNum).append('/').append(numModules).append(' ');
115            // append module name
116            buf.append(module);
117            // pad end of module with spaces so trailing startup times will line up
118            int len = module.toString().length();
119            for (; len < longestModuleNameLength; len++) {
120                buf.append(' ');
121            }
122            out.print(buf);
123        }
124    
125        public synchronized void moduleLoaded(Artifact module) {
126        }
127    
128        public synchronized void moduleStarting(Artifact module) {
129            moduleStarted = System.currentTimeMillis();
130        }
131    
132        public synchronized void moduleStarted(Artifact module) {
133            long time = System.currentTimeMillis() - moduleStarted;        
134            StringBuffer buf = new StringBuffer();
135            buf.append(" started in ");
136            
137            String formattedTime = getFormattedTime(time);
138            if (formattedTime.startsWith("0.")) {
139                // don't display zero seconds
140                formattedTime = " " +formattedTime.substring(1);
141            }
142            
143            // if first number (e.g. seconds or minutes) is one digit,
144            // pad it with a leading space to get times to line up nicely
145            int index = formattedTime.indexOf(':'); // must look for colon first
146            if (index == -1)
147                index = formattedTime.indexOf('.');
148                    
149            if (index == 1)
150                buf.append(' ');
151                
152            buf.append(formattedTime);
153            
154            out.println(buf.toString());
155        }
156    
157        public synchronized void startupFinished() {
158            long time = System.currentTimeMillis() - started;
159            out.println("Startup completed in " + getFormattedTime(time) + " seconds");
160            StartupMonitorUtil.wrapUp(out, kernel);
161        }
162    
163        public synchronized void serverStartFailed(Exception problem) {
164            out.println("Server Startup failed");
165            out.println();
166            problem.printStackTrace(out);
167        }
168    
169        // time formatting method - thanks to Maven 
170        private static String getFormattedTime( long time )
171        {
172            String pattern = "s.SSS's'";
173            if ( time / 60000L > 0 )
174            {
175                pattern = "m:s" + pattern;
176                if ( time / 3600000L > 0 )
177                {
178                    pattern = "H:m" + pattern;
179                }
180            }
181            DateFormat fmt = new SimpleDateFormat( pattern );
182            fmt.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
183            return fmt.format( new Date( time ) );
184        }
185    }