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