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 = 70; 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 int space = currentOperation.indexOf(' ', 5); 179 buf.append(currentOperation.substring(0, space + 1)); 180 // "Foo BarBarBar" limit 9 = "Foo ...ar" = 13 - 9 + 3 + 1 + 3 181 // buf.append("...").append(currentOperation.substring(currentOperation.length()-operationLimit+space+4)); 182 // "FooBar BarBarBar" limit 12 = "FooBar Ba..." = (7, 12-3) 183 buf.append(currentOperation.substring(space + 1, operationLimit - 3)).append("..."); 184 } else { 185 buf.append(currentOperation); 186 for (int i = currentOperation.length(); i < operationLimit; i++) { 187 buf.append(' '); 188 } 189 } 190 out.print(buf.toString()); 191 out.flush(); 192 } 193 194 private class UpdateThread extends Thread { 195 private volatile boolean done = false; 196 197 public UpdateThread() { 198 super("Progress Display Update Thread"); 199 setDaemon(true); 200 } 201 202 public void run() { 203 while (!done) { 204 try { 205 Thread.sleep(500); 206 } catch (InterruptedException e) { 207 continue; 208 } 209 repaint(); 210 } 211 212 repaint(); 213 out.println(); 214 StartupMonitorUtil.wrapUp(ProgressBarStartupMonitor.this.out, ProgressBarStartupMonitor.this.kernel); 215 } 216 } 217 }