KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > proxool > admin > servlet > AdminServlet


1 /*
2  * This software is released under a licence similar to the Apache Software Licence.
3  * See org.logicalcobwebs.proxool.package.html for details.
4  * The latest version is available at http://proxool.sourceforge.net
5  */

6 package org.logicalcobwebs.proxool.admin.servlet;
7
8 import org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogFactory;
10 import org.logicalcobwebs.proxool.*;
11 import org.logicalcobwebs.proxool.admin.SnapshotIF;
12 import org.logicalcobwebs.proxool.admin.StatisticsIF;
13
14 import javax.servlet.ServletConfig JavaDoc;
15 import javax.servlet.ServletException JavaDoc;
16 import javax.servlet.ServletOutputStream JavaDoc;
17 import javax.servlet.http.HttpServlet JavaDoc;
18 import javax.servlet.http.HttpServletRequest JavaDoc;
19 import javax.servlet.http.HttpServletResponse JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.text.DateFormat JavaDoc;
22 import java.text.DecimalFormat JavaDoc;
23 import java.text.SimpleDateFormat JavaDoc;
24 import java.util.Calendar JavaDoc;
25 import java.util.Date JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.Properties JavaDoc;
28
29 /**
30  * Use this to admin each pool within Proxool. It acts like a normal
31  * servlet., so just configure it within your web app as you see fit.
32  * For example, within web.xml:
33  * <pre>
34  * &lt;servlet&gt;
35  * &lt;servlet-name&gt;Admin&lt;/servlet-name&gt;
36  * &lt;servlet-class&gt;org.logicalcobwebs.proxool.admin.servlet.AdminServlet&lt;/servlet-class&gt;
37  * &lt;init-param&gt;
38  * &lt;param-name&gt;output&lt;/param-name&gt;
39  * &lt;param-value&gt;full|simple&lt;/param-value&gt;
40  * &lt;/init-param&gt;
41  * &lt;init-param&gt;
42  * &lt;param-name&gt;cssFile&lt;/param-name&gt;
43  * &lt;param-value&gt;/my_path/my.css&lt;/param-value&gt;
44  * &lt;/init-param&gt;
45  * &lt;/servlet&gt;
46  * &lt;servlet-mapping&gt;
47  * &lt;servlet-name&gt;Admin&lt;/servlet-name&gt;
48  * &lt;url-pattern&gt;/proxool&lt;/url-pattern&gt;
49  * &lt;/servlet-mapping&gt;
50  * </pre>
51  *
52  * Options:
53  * <ul>
54  * <li>output: full|simple. "full" means with HTML header and body tags "simple" means
55  * just the HTML. Choose "simple" if you are including this servlet within your own
56  * web page. Note that if you choose simple output then you're probably going to want
57  * to consider supplying some CSS to make it look nice.</li>
58  * <li>cssFile: If you choose full output (see above) then some CSS is included, inline,
59  * in the HTML header. If you specify a URL here then that file is also linked to. It is
60  * linked after the inline CSS so you only have to override thos styles you want to be
61  * different.</li>
62  * </ul>
63  *
64  * @author bill
65  * @author $Author: billhorsman $ (current maintainer)
66  * @version $Revision: 1.14 $, $Date: 2006/06/09 17:32:54 $
67  * @since Proxool 0.7
68  */

69 public class AdminServlet extends HttpServlet JavaDoc {
70
71     private static final Log LOG = LogFactory.getLog(AdminServlet.class);
72
73     /**
74      * The CSS class for a connection in different states:
75      * <ul>
76      * <li>null</li>
77      * <li>available</li>
78      * <li>active</li>
79      * <li>offline</li>
80      * </ul>
81      */

82     private static final String JavaDoc[] STATUS_CLASSES = {"null", "available", "active", "offline"};
83
84     /**
85      * OUtput full HTML including &lt;HTML&gt;, &lt;HEAD&gt; and &lt;BODY&gt; tags.
86      * @see #output
87      * @see AdminServlet configuration
88      */

89     public static final String JavaDoc OUTPUT_FULL = "full";
90
91     /**
92      * OUtput simple HTML <em>excluding</em> &lt;HTML&gt;, &lt;HEAD&gt; and &lt;BODY&gt; tags.
93      * @see #output
94      * @see AdminServlet configuration
95      */

96     public static final String JavaDoc OUTPUT_SIMPLE = "simple";
97
98     /**
99      * Either {@link #OUTPUT_FULL} (default) or {@link #OUTPUT_SIMPLE}
100      * @see AdminServlet configuration
101      */

102     private String JavaDoc output;
103
104     /**
105      * A valid URLL that can be linked to to override default, inline CSS.
106      * @see AdminServlet configuration
107      */

108
109     private String JavaDoc cssFile;
110
111     /**
112      * Used as part of the CSS class
113      */

114     private static final String JavaDoc STATISTIC = "statistic";
115
116     /**
117      * Used as part of the CSS class
118      */

119     private static final String JavaDoc CORE_PROPERTY = "core-property";
120
121     /**
122      * Used as part of the CSS class
123      */

124     private static final String JavaDoc STANDARD_PROPERTY = "standard-property";
125
126     /**
127      * Used as part of the CSS class
128      */

129     private static final String JavaDoc DELEGATED_PROPERTY = "delegated-property";
130
131     /**
132      * Used as part of the CSS class
133      */

134     private static final String JavaDoc SNAPSHOT = "snapshot";
135
136     public void init(ServletConfig JavaDoc servletConfig) throws ServletException JavaDoc {
137         super.init(servletConfig);
138
139         // Get output parameter. Default to OUTPUT_FULL.
140
output = servletConfig.getInitParameter("output");
141         if (output != null) {
142             if (output.equalsIgnoreCase(OUTPUT_FULL)) {
143                 output = OUTPUT_FULL;
144             } else if (output.equalsIgnoreCase(OUTPUT_SIMPLE)) {
145                 output = OUTPUT_SIMPLE;
146             } else {
147                 LOG.warn("Unrecognised output parameter for " + this.getClass().getName() + ". Expected: " + OUTPUT_FULL + " or " + OUTPUT_SIMPLE);
148                 output = null;
149             }
150         }
151         if (output == null) {
152             output = OUTPUT_FULL;
153         }
154
155         cssFile = servletConfig.getInitParameter("cssFile");
156
157     }
158
159     /**
160      * HH:mm:ss
161      * @see #formatMilliseconds
162      */

163     private static final DateFormat JavaDoc TIME_FORMAT = new SimpleDateFormat JavaDoc("HH:mm:ss");
164
165     /**
166      * dd-MMM-yyyy HH:mm:ss
167      */

168     private static final DateFormat JavaDoc DATE_FORMAT = new SimpleDateFormat JavaDoc("dd-MMM-yyyy HH:mm:ss");
169
170     private static final DecimalFormat JavaDoc DECIMAL_FORMAT = new DecimalFormat JavaDoc("0.00");
171
172     private static final String JavaDoc DETAIL = "detail";
173     private static final String JavaDoc DETAIL_MORE = "more";
174     private static final String JavaDoc DETAIL_LESS = "less";
175
176     /**
177      * The request parameter name that defines:
178      * <ol>
179      * <li>{@link #TAB_DEFINITION} (default)</li>
180      * <li>{@link #TAB_SNAPSHOT}</li>
181      * <li>{@link #TAB_STATISTICS}</li>
182      * </ol>
183      */

184     private static final String JavaDoc TAB = "tab";
185
186     /**
187      * @see #TAB
188      */

189     private static final String JavaDoc TAB_DEFINITION = "definition";
190
191     /**
192      * @see #TAB
193      */

194     private static final String JavaDoc TAB_SNAPSHOT = "snapshot";
195
196     /**
197      * @see #TAB
198      */

199     private static final String JavaDoc TAB_STATISTICS = "statistics";
200
201     /**
202      * The request parameter name that defines the pool
203      */

204     private static final String JavaDoc ALIAS = "alias";
205
206     /**
207      * If we are drilling down into a connection (on the {@link #TAB_SNAPSHOT snapshot} tab then
208      * this points to the {@link org.logicalcobwebs.proxool.ProxyConnection#getId() ID} we are
209      * getting detailed information for.
210      */

211     private static final String JavaDoc CONNECTION_ID = "id";
212
213     /**
214      * Delegate to {@link #doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}
215      */

216     protected void doPost(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws ServletException JavaDoc, IOException JavaDoc {
217         doGet(request, response);
218     }
219
220     /**
221      * Show the details for a pool.
222      */

223     protected void doGet(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws ServletException JavaDoc, IOException JavaDoc {
224
225         response.setHeader("Pragma", "no-cache");
226         String JavaDoc link = request.getRequestURI();
227
228         // Check the alias and if not defined and there is only one
229
// then use that.
230
String JavaDoc alias = request.getParameter(ALIAS);
231         // Check we can find the pool.
232
ConnectionPoolDefinitionIF def = null;
233         if (alias != null) {
234             try {
235                 def = ProxoolFacade.getConnectionPoolDefinition(alias);
236             } catch (ProxoolException e) {
237                 alias = null;
238             }
239         }
240         String JavaDoc[] aliases = ProxoolFacade.getAliases();
241         if (alias == null) {
242             if (aliases.length > 0) {
243                 alias = aliases[0];
244             }
245         }
246         if (def == null && alias != null) {
247             try {
248                 def = ProxoolFacade.getConnectionPoolDefinition(alias);
249             } catch (ProxoolException e) {
250                 throw new ServletException JavaDoc("Couldn't find pool with alias " + alias);
251             }
252         }
253
254         String JavaDoc tab = request.getParameter(TAB);
255         if (tab == null) {
256             tab = TAB_DEFINITION;
257         }
258
259         // If we are showing the snapshot, are we showing it in detail or not?
260
String JavaDoc snapshotDetail = request.getParameter(DETAIL);
261
262         // If we are showing the snapshot, are we drilling down into a connection?
263
String JavaDoc snapshotConnectionId = request.getParameter(CONNECTION_ID);
264
265         try {
266             if (output.equals(OUTPUT_FULL)) {
267                 response.setContentType("text/html");
268                 openHtml(response.getOutputStream());
269             }
270             response.getOutputStream().println("<div class=\"version\">Proxool " + Version.getVersion() + "</div>");
271             doList(response.getOutputStream(), alias, tab, link);
272             // Skip everything if there aren't any pools
273
if (aliases != null && aliases.length > 0) {
274                 StatisticsIF[] statisticsArray = ProxoolFacade.getStatistics(alias);
275                 final boolean statisticsAvailable = (statisticsArray != null && statisticsArray.length > 0);
276                 final boolean statisticsComingSoon = def.getStatistics() != null;
277                 // We can't be on the statistics tab if there are no statistics
278
if (!statisticsComingSoon && tab.equals(TAB_STATISTICS)) {
279                     tab = TAB_DEFINITION;
280                 }
281                 doTabs(response.getOutputStream(), alias, link, tab, statisticsAvailable, statisticsComingSoon);
282                 if (tab.equals(TAB_DEFINITION)) {
283                     doDefinition(response.getOutputStream(), def);
284                 } else if (tab.equals(TAB_SNAPSHOT)) {
285                     doSnapshot(response.getOutputStream(), def, link, snapshotDetail, snapshotConnectionId);
286                 } else if (tab.equals(TAB_STATISTICS)) {
287                     doStatistics(response.getOutputStream(), statisticsArray, def);
288                 } else {
289                     throw new ServletException JavaDoc("Unrecognised tab '" + tab + "'");
290                 }
291             }
292         } catch (ProxoolException e) {
293             throw new ServletException JavaDoc("Problem serving Proxool Admin", e);
294         }
295
296         if (output.equals(OUTPUT_FULL)) {
297             closeHtml(response.getOutputStream());
298         }
299
300     }
301
302     /**
303      * Output the tabs that we are showing at the top of the page
304      * @param out where to write the HTNL to
305      * @param alias the current pool
306      * @param link the URL to get back to this servlet
307      * @param tab the active tab
308      * @param statisticsAvailable whether statistics are available (true if configured and ready)
309      * @param statisticsComingSoon whether statistics will be available (true if configured but not ready yet)
310      */

311     private void doTabs(ServletOutputStream JavaDoc out, String JavaDoc alias, String JavaDoc link, String JavaDoc tab, boolean statisticsAvailable, boolean statisticsComingSoon) throws IOException JavaDoc {
312         out.println("<ul>");
313         out.println("<li class=\"" + (tab.equals(TAB_DEFINITION) ? "active" : "inactive") + "\"><a class=\"quiet\" HREF=\"" + link + "?alias=" + alias + "&tab=" + TAB_DEFINITION + "\">Definition</a></li>");
314         out.println("<li class=\"" + (tab.equals(TAB_SNAPSHOT) ? "active" : "inactive") + "\"><a class=\"quiet\" HREF=\"" + link + "?alias=" + alias + "&tab=" + TAB_SNAPSHOT + "\">Snapshot</a></li>");
315         if (statisticsAvailable) {
316             out.println("<li class=\"" + (tab.equals(TAB_STATISTICS) ? "active" : "inactive") + "\"><a class=\"quiet\" HREF=\"" + link + "?alias=" + alias + "&tab=" + TAB_STATISTICS + "\">Statistics</a></li>");
317         } else if (statisticsComingSoon) {
318             out.println("<li class=\"disabled\">Statistics</li>");
319         }
320         out.println("</ul>");
321     }
322
323     /**
324      * Output the statistics. If there are more than one set of statistics then show them all.
325      * @param out where to write HTML to
326      * @param statisticsArray the statistics we have ready to see
327      * @param cpd defines the connection
328      */

329     private void doStatistics(ServletOutputStream JavaDoc out, StatisticsIF[] statisticsArray, ConnectionPoolDefinitionIF cpd) throws IOException JavaDoc {
330
331         for (int i = 0; i < statisticsArray.length; i++) {
332             StatisticsIF statistics = statisticsArray[i];
333
334             openDataTable(out);
335
336             printDefinitionEntry(out, ProxoolConstants.ALIAS, cpd.getAlias(), CORE_PROPERTY);
337
338             // Period
339
printDefinitionEntry(out, "Period", TIME_FORMAT.format(statistics.getStartDate()) + " to " + TIME_FORMAT.format(statistics.getStopDate()), STATISTIC);
340
341             // Served
342
printDefinitionEntry(out, "Served", statistics.getServedCount() + " (" + DECIMAL_FORMAT.format(statistics.getServedPerSecond()) + "/s)", STATISTIC);
343
344             // Refused
345
printDefinitionEntry(out, "Refused", statistics.getRefusedCount() + " (" + DECIMAL_FORMAT.format(statistics.getRefusedPerSecond()) + "/s)", STATISTIC);
346
347             // averageActiveTime
348
printDefinitionEntry(out, "Average active time", DECIMAL_FORMAT.format(statistics.getAverageActiveTime() / 1000) + "s", STATISTIC);
349
350             // activityLevel
351
StringBuffer JavaDoc activityLevelBuffer = new StringBuffer JavaDoc();
352             int activityLevel = (int) (100 * statistics.getAverageActiveCount() / cpd.getMaximumConnectionCount());
353             activityLevelBuffer.append(activityLevel);
354             activityLevelBuffer.append("%<br/>");
355             String JavaDoc[] colours = {"0000ff", "eeeeee"};
356             int[] lengths = {activityLevel, 100 - activityLevel};
357             drawBarChart(activityLevelBuffer, colours, lengths);
358             printDefinitionEntry(out, "Activity level", activityLevelBuffer.toString(), STATISTIC);
359
360             closeTable(out);
361         }
362     }
363
364     /**
365      * We can draw a bar chart simply enough. The two arrays passed as parameters must be of equal length
366      * @param out where to write the HTML
367      * @param colours the colur (CSS valid string) for each segment
368      * @param lengths the length of each segment. Can be any size since the chart just takes up as much room
369      * as possible as uses the relative length of each segment.
370      */

371     private void drawBarChart(StringBuffer JavaDoc out, String JavaDoc[] colours, int[] lengths) {
372         out.append("<table style=\"margin: 8px; font-size: 50%;\" width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr>");
373
374         // Calculate total length
375
int totalLength = 0;
376         for (int i = 0; i < colours.length; i++) {
377             totalLength += lengths[i];
378         }
379
380         // Draw segments
381
for (int j = 0; j < colours.length; j++) {
382             String JavaDoc colour = colours[j];
383             int length = lengths[j];
384             if (length > 0) {
385                 out.append("<td style=\"background-color: #");
386                 out.append(colour);
387                 out.append("\" width=\"");
388                 out.append(100 * length / totalLength);
389                 out.append("%\">&nbsp;</td>");
390             }
391         }
392         out.append("</tr></table>");
393     }
394
395     /**
396      * Output the {@link ConnectionPoolDefinitionIF definition}
397      * @param out where to write the HTML
398      * @param cpd the definition
399      */

400     private void doDefinition(ServletOutputStream JavaDoc out, ConnectionPoolDefinitionIF cpd) throws IOException JavaDoc {
401         openDataTable(out);
402
403         /*
404             TODO: it would be nice to have meta-data in the definition so that this is much easier.
405          */

406         printDefinitionEntry(out, ProxoolConstants.ALIAS, cpd.getAlias(), CORE_PROPERTY);
407         printDefinitionEntry(out, ProxoolConstants.DRIVER_URL, cpd.getUrl(), CORE_PROPERTY);
408         printDefinitionEntry(out, ProxoolConstants.DRIVER_CLASS, cpd.getDriver(), CORE_PROPERTY);
409         printDefinitionEntry(out, ProxoolConstants.MINIMUM_CONNECTION_COUNT, String.valueOf(cpd.getMinimumConnectionCount()), STANDARD_PROPERTY);
410         printDefinitionEntry(out, ProxoolConstants.MAXIMUM_CONNECTION_COUNT, String.valueOf(cpd.getMaximumConnectionCount()), STANDARD_PROPERTY);
411         printDefinitionEntry(out, ProxoolConstants.PROTOTYPE_COUNT, cpd.getPrototypeCount() > 0 ? String.valueOf(cpd.getPrototypeCount()) : null, STANDARD_PROPERTY);
412         printDefinitionEntry(out, ProxoolConstants.SIMULTANEOUS_BUILD_THROTTLE, String.valueOf(cpd.getSimultaneousBuildThrottle()), STANDARD_PROPERTY);
413         printDefinitionEntry(out, ProxoolConstants.MAXIMUM_CONNECTION_LIFETIME, formatMilliseconds(cpd.getMaximumConnectionLifetime()), STANDARD_PROPERTY);
414         printDefinitionEntry(out, ProxoolConstants.MAXIMUM_ACTIVE_TIME, formatMilliseconds(cpd.getMaximumActiveTime()), STANDARD_PROPERTY);
415         printDefinitionEntry(out, ProxoolConstants.HOUSE_KEEPING_SLEEP_TIME, (cpd.getHouseKeepingSleepTime() / 1000) + "s", STANDARD_PROPERTY);
416         printDefinitionEntry(out, ProxoolConstants.HOUSE_KEEPING_TEST_SQL, cpd.getHouseKeepingTestSql(), STANDARD_PROPERTY);
417         printDefinitionEntry(out, ProxoolConstants.TEST_BEFORE_USE, String.valueOf(cpd.isTestBeforeUse()), STANDARD_PROPERTY);
418         printDefinitionEntry(out, ProxoolConstants.TEST_AFTER_USE, String.valueOf(cpd.isTestAfterUse()), STANDARD_PROPERTY);
419         printDefinitionEntry(out, ProxoolConstants.RECENTLY_STARTED_THRESHOLD, formatMilliseconds(cpd.getRecentlyStartedThreshold()), STANDARD_PROPERTY);
420         printDefinitionEntry(out, ProxoolConstants.OVERLOAD_WITHOUT_REFUSAL_LIFETIME, formatMilliseconds(cpd.getOverloadWithoutRefusalLifetime()), STANDARD_PROPERTY);
421         printDefinitionEntry(out, ProxoolConstants.INJECTABLE_CONNECTION_INTERFACE_NAME, String.valueOf(cpd.getInjectableConnectionInterface()), STANDARD_PROPERTY);
422         printDefinitionEntry(out, ProxoolConstants.INJECTABLE_STATEMENT_INTERFACE_NAME, String.valueOf(cpd.getInjectableStatementInterface()), STANDARD_PROPERTY);
423         printDefinitionEntry(out, ProxoolConstants.INJECTABLE_CALLABLE_STATEMENT_INTERFACE_NAME, String.valueOf(cpd.getInjectableCallableStatementInterface()), STANDARD_PROPERTY);
424         printDefinitionEntry(out, ProxoolConstants.INJECTABLE_PREPARED_STATEMENT_INTERFACE_NAME, String.valueOf(cpd.getInjectablePreparedStatementInterface()), STANDARD_PROPERTY);
425
426         // fatalSqlExceptions
427
String JavaDoc fatalSqlExceptions = null;
428         if (cpd.getFatalSqlExceptions() != null && cpd.getFatalSqlExceptions().size() > 0) {
429             StringBuffer JavaDoc fatalSqlExceptionsBuffer = new StringBuffer JavaDoc();
430             Iterator JavaDoc i = cpd.getFatalSqlExceptions().iterator();
431             while (i.hasNext()) {
432                 String JavaDoc s = (String JavaDoc) i.next();
433                 fatalSqlExceptionsBuffer.append(s);
434                 fatalSqlExceptionsBuffer.append(i.hasNext() ? ", " : "");
435             }
436             fatalSqlExceptions = fatalSqlExceptionsBuffer.toString();
437         }
438         printDefinitionEntry(out, ProxoolConstants.FATAL_SQL_EXCEPTION, fatalSqlExceptions, STANDARD_PROPERTY);
439         printDefinitionEntry(out, ProxoolConstants.FATAL_SQL_EXCEPTION_WRAPPER_CLASS, cpd.getFatalSqlExceptionWrapper(), STANDARD_PROPERTY);
440         printDefinitionEntry(out, ProxoolConstants.STATISTICS, cpd.getStatistics(), STANDARD_PROPERTY);
441         printDefinitionEntry(out, ProxoolConstants.STATISTICS_LOG_LEVEL, cpd.getStatisticsLogLevel(), STANDARD_PROPERTY);
442         printDefinitionEntry(out, ProxoolConstants.VERBOSE, String.valueOf(cpd.isVerbose()), STANDARD_PROPERTY);
443         printDefinitionEntry(out, ProxoolConstants.TRACE, String.valueOf(cpd.isTrace()), STANDARD_PROPERTY);
444         // Now all the properties that are forwarded to the delegate driver.
445
Properties JavaDoc p = cpd.getDelegateProperties();
446         Iterator JavaDoc i = p.keySet().iterator();
447         while (i.hasNext()) {
448             String JavaDoc name = (String JavaDoc) i.next();
449             String JavaDoc value = p.getProperty(name);
450             // Better hide the password!
451
if (name.toLowerCase().indexOf("password") > -1 || name.toLowerCase().indexOf("passwd") > -1) {
452                 value = "******";
453             }
454             printDefinitionEntry(out, name + " (delegated)", value, DELEGATED_PROPERTY);
455         }
456
457         closeTable(out);
458
459     }
460
461     /**
462      * Output a {@link SnapshotIF snapshot} of the pool.
463      * @param out where to write the HTML
464      * @param cpd defines the pool
465      * @param link the URL back to this servlet
466      * @param level either {@link #DETAIL_LESS} or {@link #DETAIL_MORE}
467      * @param connectionId the connection we want to drill into (optional)
468      */

469     private void doSnapshot(ServletOutputStream JavaDoc out, ConnectionPoolDefinitionIF cpd, String JavaDoc link, String JavaDoc level, String JavaDoc connectionId) throws IOException JavaDoc, ProxoolException {
470         boolean detail = (level != null && level.equals(DETAIL_MORE));
471         SnapshotIF snapshot = ProxoolFacade.getSnapshot(cpd.getAlias(), detail);
472
473         if (snapshot != null) {
474
475             openDataTable(out);
476
477             printDefinitionEntry(out, ProxoolConstants.ALIAS, cpd.getAlias(), CORE_PROPERTY);
478
479             // dateStarted
480
printDefinitionEntry(out, "Start date", DATE_FORMAT.format(snapshot.getDateStarted()), SNAPSHOT);
481
482             // snapshot date
483
printDefinitionEntry(out, "Snapshot", TIME_FORMAT.format(snapshot.getSnapshotDate()), SNAPSHOT);
484
485             // connections
486
StringBuffer JavaDoc connectionsBuffer = new StringBuffer JavaDoc();
487             connectionsBuffer.append(snapshot.getActiveConnectionCount());
488             connectionsBuffer.append(" (active), ");
489             connectionsBuffer.append(snapshot.getAvailableConnectionCount());
490             connectionsBuffer.append(" (available), ");
491             if (snapshot.getOfflineConnectionCount() > 0) {
492                 connectionsBuffer.append(snapshot.getOfflineConnectionCount());
493                 connectionsBuffer.append(" (offline), ");
494             }
495             connectionsBuffer.append(snapshot.getMaximumConnectionCount());
496             connectionsBuffer.append(" (max)<br/>");
497             String JavaDoc[] colours = {"ff9999", "66cc66", "cccccc"};
498             int[] lengths = {snapshot.getActiveConnectionCount(), snapshot.getAvailableConnectionCount(),
499                     snapshot.getMaximumConnectionCount() - snapshot.getActiveConnectionCount() - snapshot.getAvailableConnectionCount()};
500             drawBarChart(connectionsBuffer, colours, lengths);
501             printDefinitionEntry(out, "Connections", connectionsBuffer.toString(), SNAPSHOT);
502
503             // servedCount
504
printDefinitionEntry(out, "Served", String.valueOf(snapshot.getServedCount()), SNAPSHOT);
505
506             // refusedCount
507
printDefinitionEntry(out, "Refused", String.valueOf(snapshot.getRefusedCount()), SNAPSHOT);
508
509             if (!detail) {
510                 out.println(" <tr>");
511                 out.print(" <td colspan=\"2\" align=\"right\"><form action=\"" + link + "\" method=\"GET\">");
512                 out.print("<input type=\"hidden\" name=\"" + ALIAS + "\" value=\"" + cpd.getAlias() + "\">");
513                 out.print("<input type=\"hidden\" name=\"" + TAB + "\" value=\"" + TAB_SNAPSHOT + "\">");
514                 out.print("<input type=\"hidden\" name=\"" + DETAIL + "\" value=\"" + DETAIL_MORE + "\">");
515                 out.print("<input type=\"submit\" value=\"More information&gt;\">");
516                 out.println("</form></td>");
517                 out.println(" </tr>");
518             } else {
519
520                 out.println(" <tr>");
521                 out.print(" <th width=\"200\" valign=\"top\">");
522                 out.print("Details:<br>(click ID to drill down)");
523                 out.println("</th>");
524                 out.print(" <td>");
525
526                 doSnapshotDetails(out, cpd, snapshot, link, connectionId);
527
528                 out.println("</td>");
529                 out.println(" </tr>");
530
531                 long drillDownConnectionId;
532                 if (connectionId != null) {
533                     drillDownConnectionId = Long.valueOf(connectionId).longValue();
534                     ConnectionInfoIF drillDownConnection = snapshot.getConnectionInfo(drillDownConnectionId);
535                     if (drillDownConnection != null) {
536                         out.println(" <tr>");
537                         out.print(" <th valign=\"top\">");
538                         out.print("Connection #" + connectionId);
539                         out.println("</td>");
540                         out.print(" <td>");
541
542                         doDrillDownConnection(out, drillDownConnection);
543
544                         out.println("</td>");
545                         out.println(" </tr>");
546                     }
547                 }
548
549                 out.println(" <tr>");
550                 out.print(" <td colspan=\"2\" align=\"right\"><form action=\"" + link + "\" method=\"GET\">");
551                 out.print("<input type=\"hidden\" name=\"" + ALIAS + "\" value=\"" + cpd.getAlias() + "\">");
552                 out.print("<input type=\"hidden\" name=\"" + TAB + "\" value=\"" + TAB_SNAPSHOT + "\">");
553                 out.print("<input type=\"hidden\" name=\"" + DETAIL + "\" value=\"" + DETAIL_LESS + "\">");
554                 out.print("<input type=\"submit\" value=\"&lt; Less information\">");
555                 out.println("</form></td>");
556                 out.println(" </tr>");
557             }
558
559             closeTable(out);
560         }
561     }
562
563     /**
564      * If we want a {@link #DETAIL_MORE more} detailed {@link SnapshotIF snapshot} then {@link #doSnapshot(javax.servlet.ServletOutputStream, org.logicalcobwebs.proxool.ConnectionPoolDefinitionIF, String, String, String)}
565      * calls this too
566      * @param out where to write the HTML
567      * @param cpd defines the pool
568      * @param snapshot snapshot
569      * @param link the URL back to this servlet
570      * @param connectionId the connection we want to drill into (optional)
571      * @param connectionId
572      * @throws IOException
573      */

574     private void doSnapshotDetails(ServletOutputStream JavaDoc out, ConnectionPoolDefinitionIF cpd, SnapshotIF snapshot, String JavaDoc link, String JavaDoc connectionId) throws IOException JavaDoc {
575
576         long drillDownConnectionId = 0;
577         if (connectionId != null) {
578             drillDownConnectionId = Long.valueOf(connectionId).longValue();
579         }
580
581         if (snapshot.getConnectionInfos() != null && snapshot.getConnectionInfos().length > 0) {
582             out.println("<table cellpadding=\"2\" cellspacing=\"0\" border=\"0\">");
583             out.println(" <tbody>");
584
585             out.print("<tr>");
586             out.print("<td>#</td>");
587             out.print("<td align=\"center\">born</td>");
588             out.print("<td align=\"center\">last<br>start</td>");
589             out.print("<td align=\"center\">lap<br>(ms)</td>");
590             out.print("<td>&nbsp;thread</td>");
591             out.print("</tr>");
592
593             ConnectionInfoIF[] connectionInfos = snapshot.getConnectionInfos();
594             for (int i = 0; i < connectionInfos.length; i++) {
595                 ConnectionInfoIF connectionInfo = connectionInfos[i];
596
597                 if (connectionInfo.getStatus() != ConnectionInfoIF.STATUS_NULL) {
598
599                     out.print("<tr>");
600
601                     // drillDownConnectionId
602
out.print("<td style=\"background-color: #");
603                     if (connectionInfo.getStatus() == ConnectionInfoIF.STATUS_ACTIVE) {
604                         out.print("ffcccc");
605                     } else if (connectionInfo.getStatus() == ConnectionInfoIF.STATUS_AVAILABLE) {
606                         out.print("ccffcc");
607                     } else if (connectionInfo.getStatus() == ConnectionInfoIF.STATUS_OFFLINE) {
608                         out.print("ccccff");
609                     }
610                     out.print("\" style=\"");
611
612                     if (drillDownConnectionId == connectionInfo.getId()) {
613                         out.print("border: 1px solid black;");
614                         out.print("\">");
615                         out.print(connectionInfo.getId());
616                     } else {
617                         out.print("border: 1px solid transparent;");
618                         out.print("\"><a HREF=\"");
619                         out.print(link);
620                         out.print("?");
621                         out.print(ALIAS);
622                         out.print("=");
623                         out.print(cpd.getAlias());
624                         out.print("&");
625                         out.print(TAB);
626                         out.print("=");
627                         out.print(TAB_SNAPSHOT);
628                         out.print("&");
629                         out.print(DETAIL);
630                         out.print("=");
631                         out.print(DETAIL_MORE);
632                         out.print("&");
633                         out.print(CONNECTION_ID);
634                         out.print("=");
635                         out.print(connectionInfo.getId());
636                         out.print("\">");
637                         out.print(connectionInfo.getId());
638                         out.print("</a>");
639                     }
640                     out.print("</td>");
641
642                     // birth
643
out.print("<td>&nbsp;");
644                     out.print(TIME_FORMAT.format(connectionInfo.getBirthDate()));
645                     out.print("</td>");
646
647                     // started
648
out.print("<td>&nbsp;");
649                     out.print(connectionInfo.getTimeLastStartActive() > 0 ? TIME_FORMAT.format(new Date JavaDoc(connectionInfo.getTimeLastStartActive())) : "-");
650                     out.print("</td>");
651
652                     // active
653
out.print("<td align=\"right\" class=\"");
654                     out.print(getStatusClass(connectionInfo));
655                     out.print("\">");
656                     String JavaDoc active = "&nbsp;";
657                     if (connectionInfo.getTimeLastStopActive() > 0) {
658                         active = String.valueOf((int) (connectionInfo.getTimeLastStopActive() - connectionInfo.getTimeLastStartActive()));
659                     } else if (connectionInfo.getTimeLastStartActive() > 0) {
660                         active = String.valueOf((int) (snapshot.getSnapshotDate().getTime() - connectionInfo.getTimeLastStartActive()));
661                     }
662                     out.print(active);
663                     out.print("&nbsp;&nbsp;</td>");
664
665                     // requester
666
out.print("<td>&nbsp;");
667                     out.print(connectionInfo.getRequester() != null ? connectionInfo.getRequester() : "-");
668                     out.print("</td>");
669
670                     out.println("</tr>");
671                 }
672             }
673             out.println(" </tbody>");
674             out.println("</table>");
675
676         } else {
677             out.println("No connections yet");
678         }
679     }
680
681     /**
682      * What CSS class to use for a particular connection.
683      * @param info so we know the {@link org.logicalcobwebs.proxool.ConnectionInfoIF#getStatus()} status
684      * @return the CSS class
685      * @see #STATUS_CLASSES
686      */

687     private static String JavaDoc getStatusClass(ConnectionInfoIF info) {
688         try {
689             return STATUS_CLASSES[info.getStatus()];
690         } catch (ArrayIndexOutOfBoundsException JavaDoc e) {
691             LOG.warn("Unknown status: " + info.getStatus());
692             return "unknown-" + info.getStatus();
693         }
694     }
695
696     private void doDrillDownConnection(ServletOutputStream JavaDoc out, ConnectionInfoIF drillDownConnection) throws IOException JavaDoc {
697
698         // sql calls
699
String JavaDoc[] sqlCalls = drillDownConnection.getSqlCalls();
700         for (int i = 0; sqlCalls != null && i < sqlCalls.length; i++) {
701             String JavaDoc sqlCall = sqlCalls[i];
702             out.print("<div class=\"drill-down\">");
703             out.print("sql = ");
704             out.print(sqlCall);
705             out.print("</div>");
706         }
707
708         // proxy
709
out.print("<div class=\"drill-down\">");
710         out.print("proxy = ");
711         out.print(drillDownConnection.getProxyHashcode());
712         out.print("</div>");
713
714         // delegate
715
out.print("<div class=\"drill-down\">");
716         out.print("delegate = ");
717         out.print(drillDownConnection.getDelegateHashcode());
718         out.print("</div>");
719
720         // url
721
out.print("<div class=\"drill-down\">");
722         out.print("url = ");
723         out.print(drillDownConnection.getDelegateUrl());
724         out.print("</div>");
725
726     }
727
728     private void openHtml(ServletOutputStream JavaDoc out) throws IOException JavaDoc {
729         out.println("<html><header><title>Proxool Admin</title>");
730         out.println("<style media=\"screen\">");
731         out.println("body {background-color: #93bde6;}\n" +
732                 "div.version {font-weight: bold; font-size: 100%; margin-bottom: 8px;}\n" +
733                 "h1 {font-weight: bold; font-size: 100%}\n" +
734                 "option {padding: 2px 24px 2px 4px;}\n" +
735                 "input {margin: 0px 0px 4px 12px;}\n" +
736                 "table.data {font-size: 90%; border-collapse: collapse; border: 1px solid black;}\n" +
737                 "table.data th {background: #bddeff; width: 25em; text-align: left; padding-right: 8px; font-weight: normal; border: 1px solid black;}\n" +
738                 "table.data td {background: #ffffff; vertical-align: top; padding: 0px 2px 0px 2px; border: 1px solid black;}\n" +
739                 "td.null {background: yellow;}\n" +
740                 "td.available {color: black;}\n" +
741                 "td.active {color: red;}\n" +
742                 "td.offline {color: blue;}\n" +
743                 "div.drill-down {}\n" +
744                 "ul {list-style: none; padding: 0px; margin: 0px; position: relative; font-size: 90%;}\n" +
745                 "li {padding: 0px; margin: 0px 4px 0px 0px; display: inline; border: 1px solid black; border-width: 1px 1px 0px 1px;}\n" +
746                 "li.active {background: #bddeff;}\n" +
747                 "li.inactive {background: #eeeeee;}\n" +
748                 "li.disabled {background: #dddddd; color: #999999; padding: 0px 4px 0px 4px;}\n" +
749                 "a.quiet {color: black; text-decoration: none; padding: 0px 4px 0px 4px; }\n" +
750                 "a.quiet:hover {background: white;}\n");
751         out.println("</style>");
752         // If we have configured a cssFile then that will override what we have above
753
if (cssFile != null) {
754             out.println("<link rel=\"stylesheet\" media=\"screen\" type=\"text/css\" HREF=\"" + cssFile + "\"></script>");
755         }
756         out.println("</header><body>");
757     }
758
759     private void closeHtml(ServletOutputStream JavaDoc out) throws IOException JavaDoc {
760         out.println("</body></html>");
761     }
762
763     private void openDataTable(ServletOutputStream JavaDoc out) throws IOException JavaDoc {
764         out.println("<table cellpadding=\"2\" cellspacing=\"0\" border=\"1\" class=\"data\">");
765         out.println(" <tbody>");
766     }
767
768     private void closeTable(ServletOutputStream JavaDoc out) throws IOException JavaDoc {
769         out.println(" </tbody>");
770         out.println("</table>");
771         out.println("<br/>");
772     }
773
774     private void printDefinitionEntry(ServletOutputStream JavaDoc out, String JavaDoc name, String JavaDoc value, String JavaDoc type) throws IOException JavaDoc {
775         out.println(" <tr>");
776         out.print(" <th valign=\"top\">");
777         out.print(name);
778         out.println(":</th>");
779         out.print(" <td class=\"" + type + "\"nowrap>");
780         if (value != null && !value.equals("null")) {
781             out.print(value);
782         } else {
783             out.print("-");
784         }
785         out.print("</td>");
786         out.println(" </tr>");
787     }
788
789     /**
790      * Output the list of available connection pools. If there are none then display a message saying that.
791      * If there is only one then just display nothing (and the pool will displayed by default)
792      * @param out where to write the HTML
793      * @param alias identifies the current pool
794      * @param tab identifies the tab we are on so that changing pools doesn't change the tab
795      * @param link the URL back to this servlet
796      */

797     private void doList(ServletOutputStream JavaDoc out, String JavaDoc alias, String JavaDoc tab, String JavaDoc link) throws IOException JavaDoc {
798
799         String JavaDoc[] aliases = ProxoolFacade.getAliases();
800
801         if (aliases.length == 0) {
802             out.println("<p>No pools have been registered.</p>");
803         } else if (aliases.length == 1) {
804             // Don't bother listing. Just show it.
805
} else {
806             out.println("<form action=\"" + link + "\" method=\"GET\" name=\"alias\">");
807             out.println("<select name=\"alias\" size=\"" + Math.min(aliases.length, 5) + "\">");
808             for (int i = 0; i < aliases.length; i++) {
809                 out.print(" <option value=\"");
810                 out.print(aliases[i]);
811                 out.print("\"");
812                 out.print(aliases[i].equals(alias) ? " selected" : "");
813                 out.print(">");
814                 out.print(aliases[i]);
815                 out.println("</option>");
816             }
817             out.println("</select>");
818             out.println("<input name=\"" + TAB + "\" value=\"" + tab + "\" type=\"hidden\">");
819             out.println("<input value=\"Show\" type=\"submit\">");
820             out.println("</form>");
821         }
822     }
823
824     /**
825      * Express time in an easy to read HH:mm:ss format
826      *
827      * @param time in milliseconds
828      * @return time (e.g. 180000 = 00:30:00)
829      * @see #TIME_FORMAT
830      */

831     private String JavaDoc formatMilliseconds(int time) {
832         Calendar JavaDoc c = Calendar.getInstance();
833         c.clear();
834         c.add(Calendar.MILLISECOND, time);
835         return TIME_FORMAT.format(c.getTime());
836     }
837 }
838
839 /*
840 Revision history:
841 $Log: AdminServlet.java,v $
842 Revision 1.14 2006/06/09 17:32:54 billhorsman
843 Fix closing tag for select. Credit to Paolo Di Tommaso.
844
845 Revision 1.13 2006/01/18 14:39:56 billhorsman
846 Unbundled Jakarta's Commons Logging.
847
848 Revision 1.12 2005/10/07 08:23:10 billhorsman
849 Doc
850
851 Revision 1.11 2005/10/02 09:45:49 billhorsman
852 Layout
853
854 Revision 1.10 2005/09/26 21:47:46 billhorsman
855 no message
856
857 Revision 1.9 2005/09/26 13:31:14 billhorsman
858 Smartened up AdminServlet
859
860 Revision 1.8 2003/09/29 17:49:19 billhorsman
861 Includes new fatal-sql-exception-wrapper-class in display
862
863 Revision 1.7 2003/08/06 20:08:58 billhorsman
864 fix timezone display of time (for millisecond based properties)
865
866 Revision 1.6 2003/03/10 23:43:14 billhorsman
867 reapplied checkstyle that i'd inadvertently let
868 IntelliJ change...
869
870 Revision 1.5 2003/03/10 15:26:51 billhorsman
871 refactoringn of concurrency stuff (and some import
872 optimisation)
873
874 Revision 1.4 2003/03/03 11:12:00 billhorsman
875 fixed licence
876
877 Revision 1.3 2003/02/26 16:59:18 billhorsman
878 fixed spelling error in method name
879
880 Revision 1.2 2003/02/26 16:51:12 billhorsman
881 fixed units for average active time. now displays
882 properly in seconds
883
884 Revision 1.1 2003/02/24 10:19:44 billhorsman
885 moved AdminServlet into servlet package
886
887 Revision 1.1 2003/02/19 23:36:51 billhorsman
888 renamed monitor package to admin
889
890 Revision 1.10 2003/02/12 12:28:27 billhorsman
891 added url, proxyHashcode and delegateHashcode to
892 ConnectionInfoIF
893
894 Revision 1.9 2003/02/11 00:30:28 billhorsman
895 add version
896
897 Revision 1.8 2003/02/06 17:41:05 billhorsman
898 now uses imported logging
899
900 Revision 1.7 2003/02/06 15:42:21 billhorsman
901 display changes
902
903 Revision 1.6 2003/02/05 17:04:02 billhorsman
904 fixed date format
905
906 Revision 1.5 2003/02/05 15:06:16 billhorsman
907 removed dependency on JDK1.4 imaging.
908
909 Revision 1.4 2003/01/31 16:53:21 billhorsman
910 checkstyle
911
912 Revision 1.3 2003/01/31 16:38:52 billhorsman
913 doc (and removing public modifier for classes where possible)
914
915 Revision 1.2 2003/01/31 11:35:57 billhorsman
916 improvements to servlet (including connection details)
917
918 Revision 1.1 2003/01/31 00:38:22 billhorsman
919 *** empty log message ***
920
921 */
Popular Tags