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