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 org.apache.geronimo.system.serverinfo.ServerConstants; 024 025 /** 026 * A startup monitor that shows the progress of loading and starting 027 * modules using a text based progress bar and the use of line 028 * feeds to update the progress display, therefore minimizing the 029 * number of lines output to the terminal. 030 * <p/> 031 * A summary will also be produced containing a list of ports 032 * Geronimo is listening on, the configIds of application modules 033 * that were started and the URLs of Web applications that were started. 034 * 035 * @version $Revision: 1.0$ 036 */ 037 public class ProgressBarStartupMonitor implements StartupMonitor { 038 private final static char STATUS_NOT_READY = ' '; 039 private final static char STATUS_LOADING = '-'; 040 private final static char STATUS_LOADED = '>'; 041 private final static char STATUS_STARTED = '*'; 042 private final static char STATUS_FAILED = 'x'; 043 private final static int MAX_WIDTH = 79; 044 private PrintStream out; 045 private String currentOperation; 046 private Artifact[] modules; 047 private char[] moduleStatus = new char[0]; 048 private long started; 049 private int percent = 0; 050 private Kernel kernel; 051 private int operationLimit = 50; 052 private boolean finished = false; 053 private UpdateThread thread; 054 055 public synchronized void systemStarting(long startTime) { 056 out = System.out; 057 started = startTime; 058 } 059 060 public synchronized void systemStarted(Kernel kernel) { 061 out.println("Starting Geronimo Application Server v" + ServerConstants.getVersion()); 062 this.kernel = kernel; 063 currentOperation = "Loading"; 064 } 065 066 public synchronized void foundModules(Artifact[] modules) { 067 this.modules = modules; 068 moduleStatus = new char[modules.length]; 069 for (int i = 0; i < moduleStatus.length; i++) { 070 moduleStatus[i] = STATUS_NOT_READY; 071 } 072 operationLimit = MAX_WIDTH 073 - 5 // two brackets, start and stop tokens, space afterward 074 - modules.length // module tokens 075 - 4 // 2 digits of percent plus % plus space afterward 076 - 5;// 3 digits of time plus s plus space afterward 077 repaint(); 078 thread = new UpdateThread(); 079 thread.start(); 080 } 081 082 public synchronized void calculatePercent() { 083 if (finished) { 084 this.percent = 100; 085 return; 086 } 087 int percent = 0; 088 if (kernel != null) percent += 5; 089 int total = moduleStatus.length * 2; 090 int progress = 0; 091 for (int i = 0; i < moduleStatus.length; i++) { 092 char c = moduleStatus[i]; 093 switch (c) { 094 case STATUS_LOADED: 095 progress += 1; 096 break; 097 case STATUS_STARTED: 098 case STATUS_FAILED: 099 progress += 2; 100 break; 101 } 102 } 103 percent += Math.round(90f * (float) progress / (float) total); 104 this.percent = percent; 105 } 106 107 public synchronized void moduleLoading(Artifact module) { 108 currentOperation = " Loading " + module; 109 for (int i = 0; i < modules.length; i++) { 110 if (modules[i].equals(module)) { 111 moduleStatus[i] = STATUS_LOADING; 112 } 113 } 114 repaint(); 115 } 116 117 public synchronized void moduleLoaded(Artifact module) { 118 for (int i = 0; i < modules.length; i++) { 119 if (modules[i].equals(module)) { 120 moduleStatus[i] = STATUS_LOADED; 121 } 122 } 123 calculatePercent(); 124 repaint(); 125 } 126 127 public synchronized void moduleStarting(Artifact module) { 128 currentOperation = "Starting " + module; 129 } 130 131 public synchronized void moduleStarted(Artifact module) { 132 for (int i = 0; i < modules.length; i++) { 133 if (modules[i].equals(module)) { 134 moduleStatus[i] = STATUS_STARTED; 135 } 136 } 137 calculatePercent(); 138 repaint(); 139 } 140 141 public synchronized void startupFinished() { 142 finished = true; 143 currentOperation = "Startup complete"; 144 calculatePercent(); 145 thread.done = true; 146 thread.interrupt(); 147 } 148 149 public synchronized void serverStartFailed(Exception problem) { 150 currentOperation = "Startup failed"; 151 repaint(); 152 out.println(); 153 problem.printStackTrace(out); 154 } 155 156 private synchronized void repaint() { 157 StringBuffer buf = new StringBuffer(); 158 buf.append("\r["); 159 buf.append(kernel == null ? STATUS_NOT_READY : STATUS_STARTED); 160 for (int i = 0; i < moduleStatus.length; i++) { 161 buf.append(moduleStatus[i]); 162 } 163 buf.append(finished ? STATUS_STARTED : STATUS_NOT_READY); 164 buf.append("] "); 165 if (percent < 10) { 166 buf.append(' '); 167 } 168 buf.append(percent).append("% "); 169 int time = Math.round((float) (System.currentTimeMillis() - started) / 1000f); 170 if (time < 10) { 171 buf.append(' '); 172 } 173 if (time < 100) { 174 buf.append(' '); 175 } 176 buf.append(time).append("s "); 177 if (currentOperation.length() > operationLimit) { 178 if (operationLimit > 3) { 179 buf.append(currentOperation.substring(0, operationLimit - 3)).append("..."); 180 } else { 181 for (int i = 0; i < operationLimit; i++) { 182 buf.append('.'); 183 } 184 } 185 // int space = currentOperation.indexOf(' ', 5); 186 // buf.append(currentOperation.substring(0, space + 1)); 187 // "Foo BarBarBar" limit 9 = "Foo ...ar" = 13 - 9 + 3 + 1 + 3 188 // buf.append("...").append(currentOperation.substring(currentOperation.length()-operationLimit+space+4)); 189 // "FooBar BarBarBar" limit 12 = "FooBar Ba..." = (7, 12-3) 190 // buf.append(currentOperation.substring(space + 1, operationLimit - 3)).append("..."); 191 } else { 192 buf.append(currentOperation); 193 for (int i = currentOperation.length(); i < operationLimit; i++) { 194 buf.append(' '); 195 } 196 } 197 out.print(buf.toString()); 198 out.flush(); 199 } 200 201 private class UpdateThread extends Thread { 202 private volatile boolean done = false; 203 204 public UpdateThread() { 205 super("Progress Display Update Thread"); 206 setDaemon(true); 207 } 208 209 public void run() { 210 while (!done) { 211 try { 212 Thread.sleep(500); 213 } catch (InterruptedException e) { 214 continue; 215 } 216 repaint(); 217 } 218 219 repaint(); 220 out.println(); 221 StartupMonitorUtil.wrapUp(ProgressBarStartupMonitor.this.out, ProgressBarStartupMonitor.this.kernel); 222 } 223 } 224 }