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 }