| 1 |
/****************************************************************************** |
|---|
| 2 |
|
|---|
| 3 |
@file servlets.d |
|---|
| 4 |
|
|---|
| 5 |
Here's some contrived servlets to give you an idea what Mango does. |
|---|
| 6 |
|
|---|
| 7 |
Point your Browser at http://127.0.0.1 and try the following paths: |
|---|
| 8 |
|
|---|
| 9 |
1) /example/echo should return a bunch of diagnostic stuff back to |
|---|
| 10 |
the browser |
|---|
| 11 |
|
|---|
| 12 |
2) /example/ping maintains a count of how many times a particular |
|---|
| 13 |
ip-address has made a request, and check to see if Google News |
|---|
| 14 |
page has been updated since the last visit (per address). This |
|---|
| 15 |
is a hideously contrived example of VirtualCache and HttpClient. |
|---|
| 16 |
That is, it illustrates how to maintain lightweight server-side |
|---|
| 17 |
state (when necessary), and how to make client-side requests to |
|---|
| 18 |
a remote server. One might handle state management using cookies |
|---|
| 19 |
or url-rewrites instead. |
|---|
| 20 |
|
|---|
| 21 |
3) /admin/logger allows you to modify current Loggers and Levels, |
|---|
| 22 |
as well as the ability to create new Logger/Level combinations. |
|---|
| 23 |
|
|---|
| 24 |
4) all other paths are mapped to a file-request handler. Requesting |
|---|
| 25 |
/index.html should return the doxygen page for Mango; all other |
|---|
| 26 |
links should operate correctly. Be sure to start the executable |
|---|
| 27 |
from the mango/obj directory, otherwise you'll probably run into |
|---|
| 28 |
404-Not-Found errors. |
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
Kris, May 2nd 2004 |
|---|
| 32 |
Scott Sanders, June 1, 2004 |
|---|
| 33 |
|
|---|
| 34 |
*******************************************************************************/ |
|---|
| 35 |
|
|---|
| 36 |
// for a variety of servlet IO |
|---|
| 37 |
import mango.io.Uri, |
|---|
| 38 |
mango.io.Socket, |
|---|
| 39 |
mango.io.Exception, |
|---|
| 40 |
mango.io.FileBucket, |
|---|
| 41 |
mango.io.DisplayWriter, |
|---|
| 42 |
mango.io.PickleRegistry; |
|---|
| 43 |
|
|---|
| 44 |
// for numeric conversion |
|---|
| 45 |
import mango.convert.Integer; |
|---|
| 46 |
|
|---|
| 47 |
// for threads |
|---|
| 48 |
import mango.sys.System; |
|---|
| 49 |
|
|---|
| 50 |
//for logging |
|---|
| 51 |
import mango.log.Admin, |
|---|
| 52 |
mango.log.Logger, |
|---|
| 53 |
mango.log.Configurator; |
|---|
| 54 |
|
|---|
| 55 |
// for testing the http server |
|---|
| 56 |
import mango.http.server.HttpServer; |
|---|
| 57 |
|
|---|
| 58 |
// for testing the http client |
|---|
| 59 |
import mango.http.client.HttpClient; |
|---|
| 60 |
|
|---|
| 61 |
// for testing the servlet-engine |
|---|
| 62 |
import mango.servlet.Servlet, |
|---|
| 63 |
mango.servlet.ServletContext, |
|---|
| 64 |
mango.servlet.ServletProvider; |
|---|
| 65 |
|
|---|
| 66 |
// for working with cache entries |
|---|
| 67 |
import mango.cache.Payload, |
|---|
| 68 |
mango.cache.VirtualCache; |
|---|
| 69 |
|
|---|
| 70 |
// setup a logger for module scope |
|---|
| 71 |
private Logger mainLogger; |
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 |
/******************************************************************************* |
|---|
| 75 |
|
|---|
| 76 |
Directive to include the winsock2 library |
|---|
| 77 |
|
|---|
| 78 |
*******************************************************************************/ |
|---|
| 79 |
|
|---|
| 80 |
version (Win32) |
|---|
| 81 |
pragma (lib, "wsock32"); |
|---|
| 82 |
|
|---|
| 83 |
|
|---|
| 84 |
/******************************************************************************* |
|---|
| 85 |
|
|---|
| 86 |
an HTML wrapper built upon a DisplayWriter |
|---|
| 87 |
|
|---|
| 88 |
*******************************************************************************/ |
|---|
| 89 |
|
|---|
| 90 |
class HtmlWriter : DisplayWriter |
|---|
| 91 |
{ |
|---|
| 92 |
/*********************************************************************** |
|---|
| 93 |
|
|---|
| 94 |
***********************************************************************/ |
|---|
| 95 |
|
|---|
| 96 |
this (IWriter writer) |
|---|
| 97 |
{ |
|---|
| 98 |
super (writer.getBuffer); |
|---|
| 99 |
} |
|---|
| 100 |
|
|---|
| 101 |
/*********************************************************************** |
|---|
| 102 |
|
|---|
| 103 |
***********************************************************************/ |
|---|
| 104 |
|
|---|
| 105 |
override IWriter newline() |
|---|
| 106 |
{ |
|---|
| 107 |
return super.put ("<br>\r\n"c); |
|---|
| 108 |
} |
|---|
| 109 |
} |
|---|
| 110 |
|
|---|
| 111 |
|
|---|
| 112 |
/******************************************************************************* |
|---|
| 113 |
|
|---|
| 114 |
Servlet to return a file. |
|---|
| 115 |
|
|---|
| 116 |
*******************************************************************************/ |
|---|
| 117 |
|
|---|
| 118 |
class FileServlet : MethodServlet |
|---|
| 119 |
{ |
|---|
| 120 |
private static Logger logger; |
|---|
| 121 |
|
|---|
| 122 |
/*********************************************************************** |
|---|
| 123 |
|
|---|
| 124 |
get a Logger for this class |
|---|
| 125 |
|
|---|
| 126 |
***********************************************************************/ |
|---|
| 127 |
|
|---|
| 128 |
static this () |
|---|
| 129 |
{ |
|---|
| 130 |
logger = Logger.getLogger ("mango.servlets.File"); |
|---|
| 131 |
} |
|---|
| 132 |
|
|---|
| 133 |
/*********************************************************************** |
|---|
| 134 |
|
|---|
| 135 |
support GET requests only! All other method requests will |
|---|
| 136 |
return an error to the user-agent |
|---|
| 137 |
|
|---|
| 138 |
***********************************************************************/ |
|---|
| 139 |
|
|---|
| 140 |
void doGet (IServletRequest request, IServletResponse response) |
|---|
| 141 |
{ |
|---|
| 142 |
logger.info ("request for file: " ~ request.getUri.getPath); |
|---|
| 143 |
|
|---|
| 144 |
response.copyFile (request.getContext, request.getPathInfo); |
|---|
| 145 |
} |
|---|
| 146 |
} |
|---|
| 147 |
|
|---|
| 148 |
|
|---|
| 149 |
/******************************************************************************* |
|---|
| 150 |
|
|---|
| 151 |
Servlet to return a page echoing request-details sent to the server |
|---|
| 152 |
|
|---|
| 153 |
*******************************************************************************/ |
|---|
| 154 |
|
|---|
| 155 |
class Echo : Servlet |
|---|
| 156 |
{ |
|---|
| 157 |
private static Logger logger; |
|---|
| 158 |
|
|---|
| 159 |
/*********************************************************************** |
|---|
| 160 |
|
|---|
| 161 |
get a Logger for this class |
|---|
| 162 |
|
|---|
| 163 |
***********************************************************************/ |
|---|
| 164 |
|
|---|
| 165 |
static this () |
|---|
| 166 |
{ |
|---|
| 167 |
logger = Logger.getLogger ("mango.servlets.Echo"); |
|---|
| 168 |
} |
|---|
| 169 |
|
|---|
| 170 |
/*********************************************************************** |
|---|
| 171 |
|
|---|
| 172 |
Handle all the different request methods ... |
|---|
| 173 |
|
|---|
| 174 |
***********************************************************************/ |
|---|
| 175 |
|
|---|
| 176 |
void service (IServletRequest request, IServletResponse response) |
|---|
| 177 |
{ |
|---|
| 178 |
Uri uri = request.getUri; |
|---|
| 179 |
|
|---|
| 180 |
logger.info ("request for echo"); |
|---|
| 181 |
|
|---|
| 182 |
// say we're writing html |
|---|
| 183 |
response.setContentType ("text/html"); |
|---|
| 184 |
|
|---|
| 185 |
// wrap an HtmlWriter around the response output ... |
|---|
| 186 |
HtmlWriter output = new HtmlWriter(response.getWriter); |
|---|
| 187 |
|
|---|
| 188 |
// write HTML preamble ... |
|---|
| 189 |
output ("<HTML><HEAD><TITLE>Echo</TITLE></HEAD><BODY>"c); |
|---|
| 190 |
|
|---|
| 191 |
// log everything to the output |
|---|
| 192 |
output ("------------------------"c).cr() |
|---|
| 193 |
("Uri: "c) (uri).cr() |
|---|
| 194 |
("------------------------"c).cr() |
|---|
| 195 |
("Headers:"c).cr() |
|---|
| 196 |
(request.getHeaders) |
|---|
| 197 |
("------------------------"c).cr() |
|---|
| 198 |
("Cookies:"c).cr() |
|---|
| 199 |
(request.getCookies) |
|---|
| 200 |
("------------------------"c).cr() |
|---|
| 201 |
("Parameters:"c).cr() |
|---|
| 202 |
(request.getParameters) |
|---|
| 203 |
("------------------------"c).cr(); |
|---|
| 204 |
|
|---|
| 205 |
// display the Servlet environment |
|---|
| 206 |
output ("encoding: "c) (request.getCharacterEncoding).cr() |
|---|
| 207 |
("content length: "c) (request.getContentLength).cr() |
|---|
| 208 |
("content type: "c) (request.getContentType).cr() |
|---|
| 209 |
("protocol: "c) (request.getProtocol).cr() |
|---|
| 210 |
("scheme: "c) (uri.getScheme).cr() |
|---|
| 211 |
("method: "c) (request.getMethod).cr() |
|---|
| 212 |
("host name: "c) (request.getServerName).cr() |
|---|
| 213 |
("host port: "c) (request.getServerPort).cr() |
|---|
| 214 |
("remote address: "c) (request.getRemoteAddress).cr() |
|---|
| 215 |
("remote host: "c) (request.getRemoteHost).cr() |
|---|
| 216 |
("path info: "c) (request.getPathInfo).cr() |
|---|
| 217 |
("query: "c) (uri.getQuery).cr() |
|---|
| 218 |
("path: "c) (uri.getPath).cr() |
|---|
| 219 |
("context path: "c) (request.getContextPath).cr().cr().cr(); |
|---|
| 220 |
|
|---|
| 221 |
// write HTML closure |
|---|
| 222 |
output("</BODY></HTML>"c); |
|---|
| 223 |
} |
|---|
| 224 |
} |
|---|
| 225 |
|
|---|
| 226 |
|
|---|
| 227 |
/******************************************************************************* |
|---|
| 228 |
|
|---|
| 229 |
A truly contrived example of server-side state management, and |
|---|
| 230 |
client-side http requests. |
|---|
| 231 |
|
|---|
| 232 |
*******************************************************************************/ |
|---|
| 233 |
|
|---|
| 234 |
class Ping : Servlet |
|---|
| 235 |
{ |
|---|
| 236 |
private static VirtualCache cache; |
|---|
| 237 |
private static FileBucket bucket; |
|---|
| 238 |
private static PingThread thread; |
|---|
| 239 |
private static int ping_id; |
|---|
| 240 |
|
|---|
| 241 |
/*********************************************************************** |
|---|
| 242 |
|
|---|
| 243 |
A Thread subclass to monitor external web-pages |
|---|
| 244 |
|
|---|
| 245 |
***********************************************************************/ |
|---|
| 246 |
|
|---|
| 247 |
static class PingThread |
|---|
| 248 |
{ |
|---|
| 249 |
bool halt; |
|---|
| 250 |
ulong time; |
|---|
| 251 |
int delta; |
|---|
| 252 |
int pause, |
|---|
| 253 |
content; |
|---|
| 254 |
|
|---|
| 255 |
HttpClient client; |
|---|
| 256 |
Logger logger; |
|---|
| 257 |
|
|---|
| 258 |
|
|---|
| 259 |
/************************************************************** |
|---|
| 260 |
|
|---|
| 261 |
**************************************************************/ |
|---|
| 262 |
|
|---|
| 263 |
this (MutableUri uri, int pause) |
|---|
| 264 |
{ |
|---|
| 265 |
// get a Logger for this class |
|---|
| 266 |
logger = Logger.getLogger ("mango.servlets.PingThread"); |
|---|
| 267 |
|
|---|
| 268 |
this.pause = pause; |
|---|
| 269 |
client = new HttpClient (HttpClient.Head, uri); |
|---|
| 270 |
} |
|---|
| 271 |
|
|---|
| 272 |
/************************************************************** |
|---|
| 273 |
|
|---|
| 274 |
Check the provided URL now and then to see if it |
|---|
| 275 |
has changed ... |
|---|
| 276 |
|
|---|
| 277 |
**************************************************************/ |
|---|
| 278 |
|
|---|
| 279 |
version (Ares) |
|---|
| 280 |
alias void ThreadReturn; |
|---|
| 281 |
else |
|---|
| 282 |
alias int ThreadReturn; |
|---|
| 283 |
|
|---|
| 284 |
ThreadReturn run() |
|---|
| 285 |
{ |
|---|
| 286 |
while (true) |
|---|
| 287 |
try { |
|---|
| 288 |
|
|---|
| 289 |
// should we bail out? |
|---|
| 290 |
if (halt) |
|---|
| 291 |
return 0; |
|---|
| 292 |
|
|---|
| 293 |
// reset, and set up a Host header |
|---|
| 294 |
client.reset (); |
|---|
| 295 |
client.getRequestHeaders.add (HttpHeader.Host, client.getUri.getHost); |
|---|
| 296 |
|
|---|
| 297 |
// make request |
|---|
| 298 |
client.open (); |
|---|
| 299 |
|
|---|
| 300 |
// close connection |
|---|
| 301 |
client.close (); |
|---|
| 302 |
|
|---|
| 303 |
// check return status for validity |
|---|
| 304 |
if (client.isResponseOK) |
|---|
| 305 |
{ |
|---|
| 306 |
// extract modifed date (be aware of -1 return, for no header) |
|---|
| 307 |
ulong time = client.getResponseHeaders.getDate (HttpHeader.LastModified); |
|---|
| 308 |
if (time != -1) |
|---|
| 309 |
{ |
|---|
| 310 |
if (time > this.time) |
|---|
| 311 |
{ |
|---|
| 312 |
this.time = time; |
|---|
| 313 |
++delta; |
|---|
| 314 |
} |
|---|
| 315 |
} |
|---|
| 316 |
else |
|---|
| 317 |
{ |
|---|
| 318 |
int content = client.getResponseHeaders.getInt (HttpHeader.ContentLength); |
|---|
| 319 |
if (content != this.content) |
|---|
| 320 |
{ |
|---|
| 321 |
this.content = content; |
|---|
| 322 |
++delta; |
|---|
| 323 |
} |
|---|
| 324 |
} |
|---|
| 325 |
} |
|---|
| 326 |
|
|---|
| 327 |
// see if tracing is enabled before doing a bunch of work |
|---|
| 328 |
if (logger.isEnabled (logger.Level.Trace)) |
|---|
| 329 |
{ |
|---|
| 330 |
char[16] tmp; |
|---|
| 331 |
logger.trace (Integer.format (tmp, delta)); |
|---|
| 332 |
|
|---|
| 333 |
foreach (HeaderElement header; client.getResponseHeaders()) |
|---|
| 334 |
{ |
|---|
| 335 |
logger.trace (header.name.value ~ header.value); |
|---|
| 336 |
} |
|---|
| 337 |
} |
|---|
| 338 |
|
|---|
| 339 |
// sleep for a few seconds |
|---|
| 340 |
System.sleep (pause); |
|---|
| 341 |
|
|---|
| 342 |
} catch (IOException x) |
|---|
| 343 |
logger.error ("IOException: " ~ x.toString); |
|---|
| 344 |
|
|---|
| 345 |
catch (Object x) |
|---|
| 346 |
logger.fatal ("Fatal: " ~ x.toString); |
|---|
| 347 |
return 0; |
|---|
| 348 |
} |
|---|
| 349 |
} |
|---|
| 350 |
|
|---|
| 351 |
|
|---|
| 352 |
/*********************************************************************** |
|---|
| 353 |
|
|---|
| 354 |
Each unique requesting IP address has one of these |
|---|
| 355 |
maintained on the server in a cache. When the cache |
|---|
| 356 |
fills up, LRU entries are spooled out to disk. The |
|---|
| 357 |
next request for an 'old' entry will cause it to be |
|---|
| 358 |
resurrected from disk storage, with state intact. |
|---|
| 359 |
|
|---|
| 360 |
***********************************************************************/ |
|---|
| 361 |
|
|---|
| 362 |
private static class PingEntry : Payload |
|---|
| 363 |
{ |
|---|
| 364 |
// these are serialized |
|---|
| 365 |
long delta; |
|---|
| 366 |
int count; |
|---|
| 367 |
|
|---|
| 368 |
/*************************************************************** |
|---|
| 369 |
|
|---|
| 370 |
Reset our state via the provided reader |
|---|
| 371 |
|
|---|
| 372 |
***************************************************************/ |
|---|
| 373 |
|
|---|
| 374 |
override void read (IReader input) |
|---|
| 375 |
{ |
|---|
| 376 |
input (count) (delta); |
|---|
| 377 |
} |
|---|
| 378 |
|
|---|
| 379 |
/*************************************************************** |
|---|
| 380 |
|
|---|
| 381 |
Save our state via the provided writer |
|---|
| 382 |
|
|---|
| 383 |
***************************************************************/ |
|---|
| 384 |
|
|---|
| 385 |
override void write (IWriter output) |
|---|
| 386 |
{ |
|---|
| 387 |
output (count) (delta); |
|---|
| 388 |
} |
|---|
| 389 |
|
|---|
| 390 |
/*************************************************************** |
|---|
| 391 |
|
|---|
| 392 |
ISerializable factory; used for creating new |
|---|
| 393 |
class instances, which are then primed with |
|---|
| 394 |
previously saved state. |
|---|
| 395 |
|
|---|
| 396 |
***************************************************************/ |
|---|
| 397 |
|
|---|
| 398 |
override Object create (IReader reader) |
|---|
| 399 |
{ |
|---|
| 400 |
PingEntry p = new PingEntry; |
|---|
| 401 |
p.read (reader); |
|---|
| 402 |
return p; |
|---|
| 403 |
} |
|---|
| 404 |
|
|---|
| 405 |
/*************************************************************** |
|---|
| 406 |
|
|---|
| 407 |
Return a network identifier for serializing this |
|---|
| 408 |
class. |
|---|
| 409 |
|
|---|
| 410 |
***************************************************************/ |
|---|
| 411 |
|
|---|
| 412 |
override char[] getGuid() |
|---|
| 413 |
{ |
|---|
| 414 |
return this.classinfo.name; |
|---|
| 415 |
} |
|---|
| 416 |
} |
|---|
| 417 |
|
|---|
| 418 |
|
|---|
| 419 |
/*********************************************************************** |
|---|
| 420 |
|
|---|
| 421 |
Initialize the Ping environment |
|---|
| 422 |
|
|---|
| 423 |
***********************************************************************/ |
|---|
| 424 |
|
|---|
| 425 |
static this() |
|---|
| 426 |
{ |
|---|
| 427 |
// create a file bucket for serialized PingEntry instances |
|---|
| 428 |
bucket = new FileBucket (new FilePath("bucket.bin"), FileBucket.HalfK); |
|---|
| 429 |
|
|---|
| 430 |
// create a VirtualCache to host popular PingEntry instances. |
|---|
| 431 |
// When the cache fills, LRU entries get flushed out to disk, |
|---|
| 432 |
// and then retrieved and resurrected as necessary. |
|---|
| 433 |
cache = new VirtualCache (bucket, 101); |
|---|
| 434 |
|
|---|
| 435 |
// enroll the PingEntry for serialization |
|---|
| 436 |
PickleRegistry.enroll (new PingEntry); |
|---|
| 437 |
|
|---|
| 438 |
// create a thread to poll Google News for changes ... |
|---|
| 439 |
thread = new PingThread (new MutableUri ("http", "news.google.com", "/", null), |
|---|
| 440 |
System.Interval.Second * 30); |
|---|
| 441 |
System.createThread (&thread.run, true); |
|---|
| 442 |
} |
|---|
| 443 |
|
|---|
| 444 |
/*********************************************************************** |
|---|
| 445 |
|
|---|
| 446 |
clean up when we're done |
|---|
| 447 |
|
|---|
| 448 |
***********************************************************************/ |
|---|
| 449 |
|
|---|
| 450 |
static ~this() |
|---|
| 451 |
{ |
|---|
| 452 |
thread.halt = true; |
|---|
| 453 |
bucket.close (); |
|---|
| 454 |
} |
|---|
| 455 |
|
|---|
| 456 |
/*********************************************************************** |
|---|
| 457 |
|
|---|
| 458 |
handle all service requests |
|---|
| 459 |
|
|---|
| 460 |
***********************************************************************/ |
|---|
| 461 |
|
|---|
| 462 |
void service (IServletRequest request, IServletResponse response) |
|---|
| 463 |
{ |
|---|
| 464 |
PingEntry ping; |
|---|
| 465 |
|
|---|
| 466 |
// log an info message |
|---|
| 467 |
Logger.getLogger ("mango.servlets.Ping").info ("request for ping"); |
|---|
| 468 |
|
|---|
| 469 |
// get the remote ip-address |
|---|
| 470 |
char[] ua = request.getRemoteAddress; |
|---|
| 471 |
|
|---|
| 472 |
// protect against thread collisions ... |
|---|
| 473 |
synchronized (cache) |
|---|
| 474 |
{ |
|---|
| 475 |
// seen this address before? |
|---|
| 476 |
ping = cast(PingEntry) cache.get (ua); |
|---|
| 477 |
if (ping is null) |
|---|
| 478 |
// nope; create new one |
|---|
| 479 |
cache.put (ua, ping = new PingEntry); |
|---|
| 480 |
} |
|---|
| 481 |
|
|---|
| 482 |
// bump ping count |
|---|
| 483 |
++ping.count; |
|---|
| 484 |
|
|---|
| 485 |
// has Google news been updated? |
|---|
| 486 |
long changes = thread.delta - ping.delta; |
|---|
| 487 |
ping.delta = thread.delta; |
|---|
| 488 |
|
|---|
| 489 |
// say we're writing html |
|---|
| 490 |
response.setContentType ("text/html"); |
|---|
| 491 |
|
|---|
| 492 |
// grab the response writer ... |
|---|
| 493 |
IWriter output = response.getWriter; |
|---|
| 494 |
|
|---|
| 495 |
// write HTML page ... |
|---|
| 496 |
output ("<HTML><HEAD><TITLE>Ping</TITLE></HEAD><BODY>"c) |
|---|
| 497 |
("You've visited this page "c) |
|---|
| 498 |
(ping.count) |
|---|
| 499 |
(" times. Google News has had "c) |
|---|
| 500 |
(changes) |
|---|
| 501 |
(" update(s) since your last visit."c) |
|---|
| 502 |
("</BODY></HTML>"c); |
|---|
| 503 |
} |
|---|
| 504 |
} |
|---|
| 505 |
|
|---|
| 506 |
|
|---|
| 507 |
|
|---|
| 508 |
/******************************************************************************* |
|---|
| 509 |
|
|---|
| 510 |
Create an http server with the given IProvider. Wait for console |
|---|
| 511 |
input, then quit. |
|---|
| 512 |
|
|---|
| 513 |
*******************************************************************************/ |
|---|
| 514 |
|
|---|
| 515 |
void testServer (IProvider provider) |
|---|
| 516 |
{ |
|---|
| 517 |
mainLogger.info ("starting server"); |
|---|
| 518 |
|
|---|
| 519 |
// bind to port 80 on a local address |
|---|
| 520 |
InternetAddress addr = new InternetAddress (80); |
|---|
| 521 |
|
|---|
| 522 |
// create a (1 thread) server using the IProvider to service requests |
|---|
| 523 |
HttpServer server = new HttpServer (provider, addr, 1, mainLogger); |
|---|
| 524 |
|
|---|
| 525 |
// start listening for requests (but this thread does not listen) |
|---|
| 526 |
server.start (); |
|---|
| 527 |
|
|---|
| 528 |
// send this thread to sleep for ever ... |
|---|
| 529 |
System.sleep (); |
|---|
| 530 |
|
|---|
| 531 |
// should never get here |
|---|
| 532 |
mainLogger.info ("halting server"); |
|---|
| 533 |
} |
|---|
| 534 |
|
|---|
| 535 |
|
|---|
| 536 |
/******************************************************************************* |
|---|
| 537 |
|
|---|
| 538 |
Test the servlet wrapper. We have three servlets that we map to |
|---|
| 539 |
various request paths. We take advantage of a 'default' context |
|---|
| 540 |
to serve up pages from the Mango help files. |
|---|
| 541 |
|
|---|
| 542 |
*******************************************************************************/ |
|---|
| 543 |
|
|---|
| 544 |
void testServletEngine () |
|---|
| 545 |
{ |
|---|
| 546 |
mainLogger.info ("registering servlets"); |
|---|
| 547 |
|
|---|
| 548 |
// construct a servlet-provider |
|---|
| 549 |
ServletProvider sp = new ServletProvider(); |
|---|
| 550 |
|
|---|
| 551 |
// create a context for example servlets |
|---|
| 552 |
ServletContext example = sp.addContext (new ServletContext ("/example")); |
|---|
| 553 |
|
|---|
| 554 |
// create a context for admin servlets |
|---|
| 555 |
ServletContext admin = sp.addContext (new AdminContext (sp, "/admin")); |
|---|
| 556 |
|
|---|
| 557 |
// map echo requests to our echo servlet |
|---|
| 558 |
sp.addMapping ("/echo", sp.addServlet (new Echo, "echo", example)); |
|---|
| 559 |
|
|---|
| 560 |
// map ping requests to our ping servlet |
|---|
| 561 |
sp.addMapping ("/ping", sp.addServlet (new Ping, "ping", example)); |
|---|
| 562 |
|
|---|
| 563 |
// point the default context to the mango help files |
|---|
| 564 |
sp.addContext (new ServletContext ("", "../doc/html")); |
|---|
| 565 |
|
|---|
| 566 |
// map all other requests to our file servlet |
|---|
| 567 |
sp.addMapping ("/", sp.addServlet (new FileServlet, "files")); |
|---|
| 568 |
|
|---|
| 569 |
// fire up a server |
|---|
| 570 |
testServer (sp); |
|---|
| 571 |
} |
|---|
| 572 |
|
|---|
| 573 |
/******************************************************************************* |
|---|
| 574 |
|
|---|
| 575 |
|
|---|
| 576 |
*******************************************************************************/ |
|---|
| 577 |
|
|---|
| 578 |
int main () |
|---|
| 579 |
{ |
|---|
| 580 |
BasicConfigurator.configure (); |
|---|
| 581 |
mainLogger = Logger.getLogger ("mango.servlets"); |
|---|
| 582 |
mainLogger.setLevel (mainLogger.Level.Info); |
|---|
| 583 |
|
|---|
| 584 |
try { |
|---|
| 585 |
testServletEngine(); |
|---|
| 586 |
|
|---|
| 587 |
mainLogger.info ("Done"); |
|---|
| 588 |
} catch (Exception x) |
|---|
| 589 |
{ |
|---|
| 590 |
mainLogger.error (x.msg); |
|---|
| 591 |
} |
|---|
| 592 |
return 0; |
|---|
| 593 |
} |
|---|