00001 /****************************************************************************** 00002 00003 @mainpage The Mango Tree 00004 00005 Mango is a collection of D packages with an orientation toward 00006 server-side programming. These packages may be used together 00007 or in isolation and, in many cases, can be just as applicable 00008 to client-side development. Mango is targeted for Win32 and 00009 linux platforms. 00010 00011 There are currently eight packages under the Mango Tree: 00012 00013 @li mango.io: a high-performance buffered IO package. Primary 00014 functionality includes memory Buffers, external Conduits 00015 (files, sockets, etc), file-system manipulation, several 00016 flavors of Readers and Writers (formatted data), TextFormat 00017 (printf) and TextLayout support, class serialization, 00018 tokenization, and a whole lot more. Socket support is via 00019 the gracious provision of Christopher Miller's socket module. 00020 See FilePath, FileProxy, FileConduit, FileSystem, SocketConduit, 00021 ServerSocket, MulticastSocket, SocketListener, Token, Stdin, 00022 Stdout, Reader, Writer, IPickle and PickleRegistry. 00023 00024 @li mango.http.client: An HTTP client for conversing with a remote 00025 HTTP server. Supports headers, query parameters, cookies, 00026 timeout etc. Tokenizer classes in mango.io are handy for 00027 parsing returned content. See HttpClient. 00028 00029 @li mango.http.server: an HTTP server framework is provided for 00030 implementing a variety of high performance servers based 00031 on the HTTP protocol. This is not a fully-fledged v1.1 00032 implementation. That is, it doesn't currently support 00033 'fields' or 'keep alive'. However, it happily processes 00034 each request without allocating memory, making it unusually 00035 efficient. This is an example of how D array-slicing can 00036 seriously improve runtime efficiency. An open-source HTTPS 00037 library should be fairly easy to bolt in. Modules HttpServer 00038 and IProvider are the primary entry points: you implement an 00039 instance of the latter, and hand it to the former. 00040 00041 @li mango.servlet: A servlet-style engine that sits upon 00042 mango.server. Includes most of the things that Java servlet 00043 programmers would expect, and attempts to improve in certain 00044 key areas such as the IO system. See Servlet and ServletProvider. 00045 00046 @li mango.cache: Some simple caching mechanisms. Includes MRU 00047 caching via a queue, and level-two caching (to disk) via 00048 class-serialization. Now based upon a derivative of Doug Lea's 00049 concurrent hashmap. The mango.cluster package derives from 00050 mango.cache, so it's really easy to switch between a local 00051 cache implementation and a clustered version. See ICache, 00052 IMutableCache, PlainCache, QueuedCache and VirtualCache. 00053 00054 @li mango.log: A port of the wildly popular Log4J package, for 00055 logging and tracing of runtime behaviour. See 00056 <A HREF="http://logging.apache.org/log4j/docs/documentation.html">this page</A> 00057 for an introduction to Log4J. Mango.log exposes an extensible and 00058 customizable framework, has been optimised heavily for 00059 minimal runtime overhead, does not impact the GC once 00060 initialised, and operates with either Mango.io or Phobos. 00061 Mango.log can generate remote log messages for use with Chainsaw, 00062 and has a browser-based 'Administrator' which allows remote, 00063 dynamic inspection and adjustment of the log settings within an 00064 executing program. See Logger, BasicConfigurator and 00065 PropertyConfigurator. There are a number of examples that show 00066 how to use these facilities (e.g Servlets.d) 00067 00068 @li mango.cluster: A clustering package for servers and other 00069 network aware applications. Currently supports clustered 00070 caching and queuing, where the former is limited to a fixed 00071 MRU number of entries per node, and the latter is limited to an 00072 upper memory waterline. While the underlying QOS (quality of 00073 service) substrate is setup to be plugable, the QOS 00074 currently provided is stream/multicast based. Note that this 00075 package is not a substitute for a persistence layer; instead 00076 it is a tool for enabling horizontal scaling within a system 00077 that has been designed explicitly from the outset to scale. 00078 On the other hand, it can significantly enhance the throughput 00079 of any persistence layer by offloading a large percentage of 00080 read operations. See CacheInvalidatee, CacheInvalidator, 00081 NetworkCombo, NetworkAlert, NetworkCache and NetworkQueue. 00082 00083 @li mango.icu: Set of wrappers around the ICU I18N project. See 00084 <A HREF="http://oss.software.ibm.com/icu/">this page</A> for 00085 the scoop on what is probably the most comprehensive and 00086 functional project in this particular arena. Mango.icu exposes 00087 the C API in a manner that takes advantage of D arrays and 00088 so on. See UCalendar, UChar, UConverter, UDateFormat, ULocale, 00089 UMessageFormat, UNumberFormat, UResourceBundle, UString, 00090 UText, UCollator, USet, UTransform, USearch, UNormalize, 00091 UDomainName, UBreakIterator, and UTimeZone. 00092 Numeric formatting is handled by a range of subclasses, 00093 including UDecimalFormat, UCurrencyFormat, UPercentFormat, 00094 UScientificFormat, and USpelloutFormat. 00095 There is set of adapter classes in UMango which can be used 00096 to bind the ICU converters to Mango.io, thereby enabling 00097 Reader and Writer with the full suite of unicode transcoders. 00098 00099 Package dependencies are as follows (from left to right): 00100 00101 @code 00102 mango.io => phobos (minimal) 00103 mango.log => mango.io (without -version=Isolated) 00104 mango.icu => mango.io (without -version=Isolated) 00105 mango.cache => mango.io 00106 mango.http.server => mango.io 00107 mango.http.client => mango.io, mango.server 00108 mango.cluster => mango.io, mango.cache, mango.log 00109 mango.servlet => mango.io, mango.http.server, mango.cache, mango.log 00110 @endcode 00111 00112 Mango.icu and Mango.log are also made available as independent packages, 00113 outside of the regular Mango Tree. To enable this, specify the flag 00114 -version=Isolated when building those packages 00115 00116 You might take a look at the unittest.d source to get a general 00117 feel for functionality, and browse the various pdf files 00118 <A HREF="http://svn.dsource.org/svn/projects/mango/trunk/doc/">here</A> 00119 along with the class-hierarchy or alphabetical-list linked at the 00120 top of this page. There's also a set of examples 00121 <A HREF="http://svn.dsource.org/svn/projects/mango/trunk/example/">over here</A>. 00122 Those will probably be sufficient to get an idea where the Mango Tree 00123 might come in handy within your projects. 00124 00125 Discussion forums are hosted 00126 <A HREF="http://www.dsource.org/forums/viewforum.php?f=5">here</A>, 00127 and the general introduction starts 00128 <A HREF="http://www.dsource.org/forums/viewtopic.php?t=148">here</A>. 00129 00130 *******************************************************************************/ 00131 00132 00133 00134 00135 /****************************************************************************** 00136 00137 @file unittest.d 00138 00139 Test jig for the mango.io package. 00140 00141 00142 This shows a number of different ways to manipulate buffers, 00143 readers, writers, and how to perform IO on files and sockets. 00144 00145 The basic premise behind this IO package is as follows: 00146 00147 1) the central concept is that of a buffer. The buffer acts 00148 as a queue (line) where items are removed from the front 00149 and new items are added to the back. Buffers are modeled 00150 by mango.io.model.IBuffer, and a concrete implementation 00151 is provided via mango.io.Buffer. 00152 00153 2) buffers can be written to directly, but a Reader and/or 00154 Writer are typically used to read & write formatted data. 00155 These readers & writers are bound to a specific buffer; 00156 often the same buffer. It's also perfectly legitimate to 00157 bind multiple writers to the same buffer; they will all 00158 behave serially as one would expect. The same applies to 00159 multiple readers on the same buffer. Readers and writers 00160 support two styles of IO: put/get, and the C++ style << 00161 and >> operators. All such operations can be chained. 00162 00163 3) Any class can be made compatable with the reader/writer 00164 framework by implementing the IReadable and/or IWritable 00165 interfaces. Each of these specify just a single method. 00166 00167 4) Buffers may also be tokenized. This is handy when one is 00168 dealing with text input, and/or the content suits a more 00169 fluid format than most typical readers & writers support. 00170 Tokens are mapped directly onto buffer content, so there 00171 is only minor overhead in using them. Tokens can be read 00172 and written by reader/writers also, using a more relaxed 00173 set of rules than those applied to integral IO. 00174 00175 5) buffers are sometimes memory-only, in which case there 00176 is nothing left to do when a reader (or tokenizer) hits 00177 end of buffer conditions. Other buffers are themselves 00178 bound to a Conduit. When this is the case, a reader will 00179 eventually cause the buffer to reload via its associated 00180 conduit. Previous buffer content will thus be lost. The 00181 same concept is applied to writers, whereby they flush 00182 the content of a full buffer to a bound conduit before 00183 continuing. 00184 00185 6) conduits provide virtualized access to external content, 00186 and represent things like files or Internet connections. 00187 They are just a different kind of stream. Conduits are 00188 modelled by mango.io.model.IConduit, and implemented via 00189 classes FileConduit and SocketConduit. Additional kinds 00190 of conduit are easy to construct: one either subclasses 00191 mango.io.Conduit, or implements mango.io.model.IConduit. 00192 The conduit reads and writes a buffer in large segments; 00193 typically the entire buffer. 00194 00195 7) additional file-system support is provided through two 00196 classes: FileSystem supports operations such as getting 00197 and setting the current directory, and FileProxy exposes 00198 facilities to manipulate both files and directories. 00199 00200 8) console IO is implemented via Stdio, using FileConduit 00201 and appropriate readers and writers. Console IO can be 00202 redirected in the traditional (shell) manner. 00203 00204 9) the package is intended to be portable between linux and 00205 Win32 platforms. 00206 00207 00208 Kris Bell, March 26th 2004 00209 00210 *******************************************************************************/ 00211 00212 00213 // test these modules 00214 import mango.io.Uri, 00215 mango.io.Stdin, 00216 mango.io.Stdout, 00217 mango.io.Token, 00218 mango.io.Reader, 00219 mango.io.Writer, 00220 mango.io.Buffer, 00221 mango.io.Socket, 00222 mango.io.Conduit, 00223 mango.io.FilePath, 00224 mango.io.FileStyle, 00225 mango.io.FileProxy, 00226 mango.io.Tokenizer, 00227 mango.io.TextReader, 00228 mango.io.TextWriter, 00229 mango.io.FileBucket, 00230 mango.io.FileConduit, 00231 mango.io.TextLayout, 00232 mango.io.TextFormat, 00233 mango.io.ColumnWriter, 00234 mango.io.DisplayWriter, 00235 mango.io.PickleReader, 00236 mango.io.PickleWriter, 00237 mango.io.SocketConduit, 00238 mango.io.SocketListener, 00239 mango.io.ArrayAllocator, 00240 mango.io.PickleRegistry, 00241 mango.io.DatagramSocket, 00242 mango.io.MulticastSocket; 00243 00244 // need this for logging 00245 import mango.log.Logger, 00246 mango.log.Layout, 00247 mango.log.Manager, 00248 mango.log.XmlLayout, 00249 mango.log.DateLayout, 00250 mango.log.Configurator, 00251 mango.log.FileAppender, 00252 mango.log.ConsoleAppender, 00253 mango.log.RollingFileAppender; 00254 00255 // need these for reading & writing classes 00256 import mango.io.model.IReader, 00257 mango.io.model.IWriter, 00258 mango.io.model.IPickle; 00259 00260 // add a bunch of stuff for testing the http server 00261 import mango.http.server.HttpParams, 00262 mango.http.server.HttpCookies, 00263 mango.http.server.HttpHeaders, 00264 mango.http.server.HttpServer, 00265 mango.http.server.HttpRequest, 00266 mango.http.server.HttpResponse, 00267 mango.http.server.HttpProvider; 00268 00269 import mango.http.server.model.IProvider, 00270 mango.http.server.model.IProviderBridge; 00271 00272 import mango.http.client.HttpClient; 00273 00274 import mango.servlet.Servlet, 00275 mango.servlet.ServletConfig, 00276 mango.servlet.ServletContext, 00277 mango.servlet.ServletProvider; 00278 00279 import mango.cache.PlainCache, 00280 mango.cache.HashMap, 00281 mango.cache.Payload, 00282 mango.cache.QueuedCache, 00283 mango.cache.VirtualCache; 00284 00285 import mango.cluster.Message, 00286 mango.cluster.NetworkQueue, 00287 mango.cluster.NetworkCache, 00288 mango.cluster.CacheInvalidator, 00289 mango.cluster.CacheInvalidatee; 00290 00291 import mango.cluster.qos.socket.Cluster, 00292 mango.cluster.qos.socket.ClusterServer, 00293 mango.cluster.qos.socket.ProtocolReader, 00294 mango.cluster.qos.socket.ProtocolWriter; 00295 00296 import mango.icu.UMango, 00297 mango.icu.URegex, 00298 mango.icu.UString, 00299 mango.icu.UDomainName, 00300 mango.icu.UStringPrep, 00301 mango.icu.UConverter, 00302 mango.icu.USet, 00303 mango.icu.UCollator, 00304 mango.icu.UTimeZone, 00305 mango.icu.UEnumeration, 00306 mango.icu.UMessageFormat; 00307 00308 import mango.format.Double; 00309 00310 00311 //import mango.xml.dom.all; 00312 00313 /******************************************************************************* 00314 00315 Directive for build.exe to include the winsock2 library 00316 00317 *******************************************************************************/ 00318 00319 version (build) 00320 { 00321 version (Win32) 00322 pragma (link, wsock32); 00323 } 00324 00325 /******************************************************************************* 00326 00327 global scope variables 00328 00329 *******************************************************************************/ 00330 00331 private Logger logger; 00332 00333 /******************************************************************************* 00334 00335 Simple test of in-memory buffer. Bind both a Reader and a Writer 00336 onto the same buffer. 00337 00338 *******************************************************************************/ 00339 00340 static void testBuffer() 00341 { 00342 // create a small heap buffer 00343 Buffer buf = new Buffer (256); 00344 00345 // map same buffer into both reader and writer 00346 Writer w = new Writer (buf); 00347 Reader r = new Reader (buf); 00348 00349 int i = 10; 00350 int j = 20; 00351 double d = 3.14159; 00352 char[] c = "testing"; 00353 00354 // write integral types out 00355 w (c) (i) (j) (d); 00356 00357 // read them back again 00358 r (c) (i) (j) (d); 00359 00360 assert(i==10); 00361 assert(j==20); 00362 assert(d==3.14159); 00363 assert(c=="testing"); 00364 00365 // reset 00366 buf.clear(); 00367 00368 // same thing again, but using iostream syntax instead 00369 w << c << i << j << d; 00370 00371 // read them back again 00372 r >> c >> i >> j >> d; 00373 00374 assert(i==10); 00375 assert(j==20); 00376 assert(d==3.14159); 00377 assert(c=="testing"); 00378 00379 // reset 00380 buf.clear(); 00381 00382 // same thing again, but using put() syntax instead (and swap i & j) 00383 w.put(c).put(i).put(j).put(d); 00384 r.get(c).get(j).get(i).get(d); 00385 00386 assert(i==20); 00387 assert(j==10); 00388 assert(d==3.14159); 00389 assert(c=="testing"); 00390 } 00391 00392 00393 /******************************************************************************* 00394 00395 Append to a buffer directly without using a Writer. This can be 00396 useful for appending a set of strings (or other array type) to 00397 a contiguous space in a similar fashion to std.outbuffer. 00398 00399 *******************************************************************************/ 00400 00401 static void testAppend() 00402 { 00403 char[] foo = "to write some D code"; 00404 00405 // create a small heap buffer 00406 Buffer buf = new Buffer (256); 00407 00408 // append some text directly to it 00409 buf.append ("now is the time for all good men ").append(foo); 00410 00411 // output the combined string 00412 Stdout (buf.toString) (CR); 00413 } 00414 00415 00416 /******************************************************************************* 00417 00418 write delimited text tokens to a buffer, then read them back out 00419 to the console 00420 00421 *******************************************************************************/ 00422 00423 static void testToken1() 00424 { 00425 // create a small buffer on top of a static array 00426 static ubyte[128] storage; 00427 Buffer buf = new Buffer (storage); 00428 00429 // write tokens with a comma between each 00430 IWriter write = new TextWriter (buf, ","); 00431 00432 // bind a comma-tokenizer to a token instance 00433 BoundToken token = new BoundToken (Tokenizers.comma); 00434 00435 // write some stuff to the buffer 00436 write ("now is the time for all good men") (3.14159); 00437 00438 // read it back, and display as text 00439 while (token.next (buf)) 00440 Stdout (token) (CR); 00441 } 00442 00443 /******************************************************************************* 00444 00445 Use tokens directly with reader/writer also 00446 00447 *******************************************************************************/ 00448 00449 static void testToken2() 00450 { 00451 // create a small buffer on the heap 00452 Buffer buf = new Buffer (256); 00453 00454 // write items with a comma between each 00455 IWriter write = new TextWriter (buf, ","); 00456 00457 // write some stuff to the buffer 00458 write ("now is the time for all good men") (3.14159); 00459 00460 // bind a couple of tokens to a comma tokenizer 00461 ReaderToken text = new ReaderToken (Tokenizers.comma); 00462 ReaderToken number = new ReaderToken (Tokenizers.comma); 00463 00464 // create any old reader since we only use it for handling tokens 00465 IReader read = new Reader (buf); 00466 00467 // populate both tokens via reader 00468 read (text) (number); 00469 00470 // print them to the console 00471 Stdout (text) (':') (number) (CR); 00472 } 00473 00474 /******************************************************************************* 00475 00476 use TextReader to convert text into integral types. This is akin 00477 to what scanf does. 00478 00479 *******************************************************************************/ 00480 00481 static void testToken3() 00482 { 00483 // create a small buffer 00484 Buffer buf = new Buffer (256); 00485 00486 // write tokens with a comma between each 00487 TextWriter write = new TextWriter (buf, ","); 00488 00489 // write some stuff to the buffer 00490 write (101) (3.14159); 00491 00492 // map a comma-tokenizing reader onto our buffer 00493 TextReader read = new TextReader (buf, Tokenizers.comma); 00494 00495 real pi; 00496 int integer; 00497 00498 // convert both tokens via reader 00499 read (integer) (pi); 00500 00501 // print them to the console 00502 Stdout (integer) (',') (pi) (CR); 00503 } 00504 00505 00506 /******************************************************************************* 00507 00508 Read line tokens via a TextReader 00509 00510 *******************************************************************************/ 00511 00512 static void testToken4() 00513 { 00514 // open a file for reading 00515 FileConduit fc = new FileConduit ("test.txt"); 00516 00517 // create a buffer for transferring content 00518 IBuffer buffer = fc.createBuffer (); 00519 00520 // map a line-tokenizing reader onto our buffer 00521 TextReader read = new TextReader (buffer, Tokenizers.line); 00522 00523 char[] ca; 00524 00525 // read a line of text 00526 read (ca); 00527 00528 // display it on the console 00529 Stdout (ca) (CR); 00530 } 00531 00532 00533 00534 /******************************************************************************* 00535 00536 Use printf via a wrapper class 00537 00538 *******************************************************************************/ 00539 00540 static void testFormat() 00541 { 00542 // create a Format instance 00543 TextFormat format = new TextFormat (256); 00544 00545 // write text to Stdout 00546 Stdout (format ("there are %d arguments to every %.*s", 3, "contradiction")) (CR); 00547 } 00548 00549 00550 /******************************************************************************* 00551 00552 Layout text strings in an indexed fashion 00553 00554 *******************************************************************************/ 00555 00556 static void testLayout() 00557 { 00558 // create a Layout instance 00559 LayoutChar layout = new LayoutChar (256); 00560 00561 // write text to Stdout 00562 Stdout (layout ("%2 %1", "one", "two")) (CR); 00563 } 00564 00565 00566 /******************************************************************************* 00567 00568 Use interfaces to make any class reader and/or writer compatible 00569 00570 *******************************************************************************/ 00571 00572 static void testClassIO() 00573 { 00574 // define a readable/writable class (via interfaces) 00575 class Foo : IReadable, IWritable 00576 { 00577 private int x = 11; 00578 private int y = 112; 00579 00580 void write (IWriter put) 00581 { 00582 put (x) (y); 00583 } 00584 00585 void read (IReader get) 00586 { 00587 get (x) (y); 00588 } 00589 } 00590 00591 // create a small heap buffer 00592 Buffer buf = new Buffer (256); 00593 00594 // map reader/writer onto same buffer 00595 Writer write = new Writer (buf); 00596 Reader read = new Reader (buf); 00597 00598 // construct a Foo 00599 Foo foo = new Foo(); 00600 00601 // write it 00602 write (foo); 00603 00604 // read it back 00605 read (foo); 00606 } 00607 00608 00609 /******************************************************************************* 00610 00611 Use interfaces to make any class serializable. This will be used 00612 by mango.server to move class-instances around the network. Each 00613 class is effectively a factory for itself. 00614 00615 Note that this is not the same as Java; you can't ship code with 00616 the data ... one might perhaps use dll's or something to do that. 00617 00618 *******************************************************************************/ 00619 00620 static void testClassSerialization() 00621 { 00622 // define a serializable class (via interfaces) 00623 class Bar : IPickle, IPickleFactory 00624 { 00625 private int x = 11; 00626 private int y = 112; 00627 00628 void write (IWriter write) 00629 { 00630 write (x) (y); 00631 } 00632 00633 void read (IReader read) 00634 { 00635 read (x) (y); 00636 assert (x == 11 && y == 112); 00637 } 00638 00639 Object create (IReader reader) 00640 { 00641 Bar bar = new Bar (); 00642 bar.read (reader); 00643 return bar; 00644 } 00645 00646 char[] getGuid () 00647 { 00648 return "unittest.Bar"; 00649 } 00650 } 00651 00652 static Object create (IReader reader) 00653 { 00654 Bar bar = new Bar(); 00655 bar.read (reader); 00656 return bar; 00657 } 00658 00659 // setup for serialization 00660 Buffer buf = new Buffer (256); 00661 PickleWriter w = new PickleWriter (buf); 00662 PickleReader r = new PickleReader (buf); 00663 00664 r.setAllocator (new BufferAllocator); 00665 00666 // construct a Bar 00667 Bar bar = new Bar (); 00668 00669 // tell registry about this object 00670 //PickleRegistry.enroll (&create, "unittest.Bar"); 00671 PickleRegistry.enroll (bar); 00672 00673 // serialize it 00674 w.freeze (bar); 00675 00676 // create a new instance and populate. This just shows the basic 00677 // concept, not a fully operational implementation 00678 Object o = r.thaw (); 00679 } 00680 00681 00682 /******************************************************************************* 00683 00684 open a file, and stream directly to console 00685 00686 *******************************************************************************/ 00687 00688 static void testFile4() 00689 { 00690 // open a file for reading 00691 FileConduit fc = new FileConduit ("test.txt"); 00692 00693 // stream directly to console 00694 Stdout.conduit.copy (fc); 00695 } 00696 00697 00698 /******************************************************************************* 00699 00700 Create a file for random access. Write some stuff to it, rewind to 00701 file start and read back. 00702 00703 *******************************************************************************/ 00704 00705 static void testRandomAccess() 00706 { 00707 // open a file for reading 00708 auto FileConduit fc = new FileConduit ("random.bin", FileStyle.ReadWriteCreate); 00709 00710 // construct (binary) reader & writer upon this conduit 00711 Reader read = new Reader(fc); 00712 Writer write = new Writer(fc); 00713 00714 int x=10, y=20; 00715 00716 // write some data 00717 write (x) (y); 00718 00719 // flush output since IO is buffered 00720 write (); 00721 00722 // rewind to file start 00723 fc.seek (0); 00724 00725 // read data back again, but swap destinations 00726 read (y) (x); 00727 00728 assert (y==10); 00729 assert (x==20); 00730 } 00731 00732 00733 /******************************************************************************* 00734 00735 Create a file for random access. Write some stuff to it, rewind to 00736 file start and read back. 00737 00738 *******************************************************************************/ 00739 00740 static void testConduitFilters() 00741 { 00742 class MyFilter1 : ConduitSource 00743 { 00744 int reader (void[] dst) 00745 { 00746 printf ("filtering input ...\n"); 00747 return next.reader (dst); 00748 } 00749 } 00750 00751 class MyFilter2 : ConduitSink 00752 { 00753 int writer (void[] src) 00754 { 00755 printf ("filtering output ...\n"); 00756 return next.writer (src); 00757 } 00758 } 00759 00760 // open a file for reading 00761 auto FileConduit fc = new FileConduit ("random.bin", FileStyle.ReadWriteCreate); 00762 fc.attach (new MyFilter2); 00763 fc.attach (new MyFilter1); 00764 fc.attach (new MyFilter1); 00765 00766 // construct (binary) reader & writer upon this conduit 00767 Reader read = new Reader(fc); 00768 Writer write = new Writer(fc); 00769 00770 int x=1; 00771 00772 // write some data, and flush it 00773 write (x) (); 00774 00775 // rewind to file start 00776 fc.seek (0); 00777 00778 // read data back again 00779 read (x); 00780 } 00781 00782 00783 /******************************************************************************* 00784 00785 open a file, and explicitly buffer it to another conduit. This is 00786 effectively what Conduit.copyTo() does. 00787 00788 *******************************************************************************/ 00789 00790 static void testFile5() 00791 { 00792 // open a file for reading 00793 FileConduit fc = new FileConduit ("test.txt"); 00794 00795 // create a buffer for transferring content 00796 IBuffer buffer = fc.createBuffer (); 00797 00798 // stream the data from file to stdout. This is probably as fast as 00799 // one can practically make operations of this type. 00800 while (fc.read (buffer) != fc.Eof) 00801 Stdout.conduit.write (buffer); 00802 00803 // ensure the writer actually wrote everything 00804 Stdout.conduit.flush (buffer); 00805 } 00806 00807 00808 /******************************************************************************* 00809 00810 Open a file and read it line-by-line using a line tokenizer. This 00811 uses CompositeToken to hide some of the details. 00812 00813 *******************************************************************************/ 00814 00815 static void testFile1() 00816 { 00817 // open a file for reading 00818 FileConduit fc = new FileConduit ("test.txt"); 00819 00820 // create a Token and bind it to both the file and a line-tokenizer 00821 CompositeToken line = new CompositeToken (Tokenizers.line, fc); 00822 00823 // read file a line at a time. Method next() returns false when no more 00824 // delimiters are found. Note there may be an unterminated line at eof 00825 while (line.get) 00826 Stdout (line) (CR); 00827 } 00828 00829 00830 /******************************************************************************* 00831 00832 Unwound version of above: we now explicitly pass a buffer instance 00833 to the tokenizer, although the token itself is still bound. 00834 00835 *******************************************************************************/ 00836 00837 static void testFile2() 00838 { 00839 // open a file for reading 00840 FileConduit fc = new FileConduit ("test.txt"); 00841 00842 // create a buffer for reading the file 00843 IBuffer buffer = fc.createBuffer(); 00844 00845 // bind a line-tokenizer to our input token 00846 BoundToken line = new BoundToken (Tokenizers.line); 00847 00848 // read file a line at a time. Method next() returns false when no more 00849 // delimiters are found. Note there may be an unterminated line at eof 00850 while (line.next(buffer) || line.getLength()) 00851 Stdout (line) (CR); 00852 } 00853 00854 00855 /******************************************************************************* 00856 00857 Further unwinding of above: we invoke the tokenizer directly, 00858 explicitly passing both the buffer and the token 00859 00860 *******************************************************************************/ 00861 00862 static void testFile3() 00863 { 00864 // open a file for reading 00865 FileConduit fc = new FileConduit ("test.txt"); 00866 00867 // create a buffer for reading the file 00868 IBuffer buffer = fc.createBuffer(); 00869 00870 // create a token for receiving the line 00871 Token token = new Token (); 00872 00873 // read file a line at a time. Method next() returns false when no more 00874 // delimiters are found. Note there may be an unterminated line at eof 00875 while (Tokenizers.line.next(buffer, token) || token.getLength()) 00876 Stdout.put(token).cr(); 00877 } 00878 00879 00880 /******************************************************************************* 00881 00882 Recursively scan files and directories, adding filtered files to 00883 an output structure as we go. Thanks to Chris S for this. 00884 00885 *******************************************************************************/ 00886 00887 void testScanFiles() 00888 { 00889 /*********************************************************************** 00890 00891 ***********************************************************************/ 00892 00893 struct Dependencies 00894 { 00895 FileProxy[] mods; 00896 FilePath[] pkgs; 00897 } 00898 00899 /*********************************************************************** 00900 00901 ***********************************************************************/ 00902 00903 void scanFiles (inout Dependencies deps, FilePath base) 00904 { 00905 /*************************************************************** 00906 00907 delegate for filtering sub-directories and 00908 D source files 00909 00910 ***************************************************************/ 00911 00912 bit filter (FilePath fp) 00913 { 00914 char[] sbuf = fp.getExtension(); 00915 00916 if (fp.getName[0] != '.') 00917 if (sbuf.length == 0 || sbuf == "d") 00918 return true; 00919 00920 return false; 00921 } 00922 00923 /*************************************************************** 00924 00925 ***************************************************************/ 00926 00927 FileProxy proxy = new FileProxy (base); 00928 FilePath[] paths = proxy.toList (&filter); 00929 00930 // add packages only if there's something in them 00931 if (paths.length) 00932 deps.pkgs ~= base; 00933 00934 foreach (FilePath x; paths) 00935 { 00936 // combine base path with listed file 00937 FilePath spliced = new FilePath (x.splice (base)); 00938 00939 // recurse if this is a directory ... 00940 proxy = new FileProxy (spliced); 00941 if (proxy.isDirectory) 00942 scanFiles (deps, spliced); 00943 else 00944 deps.mods ~= proxy; 00945 } 00946 } 00947 00948 00949 /*********************************************************************** 00950 00951 ***********************************************************************/ 00952 00953 Dependencies deps; 00954 scanFiles (deps, new FilePath (r"\dmd\src\mango")); 00955 00956 Stdout.put ("-----------------").cr(); 00957 foreach (FileProxy mod; deps.mods) 00958 Stdout.put (mod.getPath()).cr(); 00959 00960 Stdout.put ("-----------------").cr(); 00961 foreach (FilePath pkg; deps.pkgs) 00962 Stdout.put (pkg).cr(); 00963 } 00964 00965 00966 /******************************************************************************* 00967 00968 Open an internet connection, and copy home page to console (via 00969 Chris Miller's socket.d). We could use a line-by-line approach in 00970 the same manner as above since both Files & Sockets are conduits. 00971 All conduits are interchangable with others. 00972 00973 *******************************************************************************/ 00974 00975 static void testSocket() 00976 { 00977 // create a socket and connect it to Walter's site 00978 SocketConduit sc = new SocketConduit(); 00979 sc.connect (new InternetAddress("www.digitalmars.com", 80)); 00980 00981 // construct a writer and bind it to the socket 00982 IWriter write = new DisplayWriter (sc); 00983 00984 // send HTTP request - flush the output 00985 write ("GET /d/intro.html HTTP/1.1\r\n" 00986 "Host: www.digitalmars.com\r\n\r\n") (); 00987 00988 // set read-timeout to 0.5 seconds (avoids stalling) 00989 sc.setTimeout (System.Interval.Millisec * 500); 00990 00991 // stream home-page directly to console conduit 00992 Stdout.conduit.copy (sc); 00993 } 00994 00995 00996 /******************************************************************************* 00997 00998 Use a ColumnWriter to write formatted data onto the console. Note 00999 that we map the ColumnWriter directly into the Stdout buffer. 01000 01001 *******************************************************************************/ 01002 01003 static void testColumn() 01004 { 01005 static int[] columns = [0, 4, 14, 24]; 01006 01007 // map a ColumnWriter directly onto Stdout 01008 ColumnWriter cw = new ColumnWriter (Stdout.getBuffer(), new ColumnList(columns)); 01009 01010 cw (1) (20.34) ("test") ("next") (CR) (); 01011 } 01012 01013 /******************************************************************************* 01014 01015 Get a line of input from the console, and extract an integer. Input 01016 from the console always waits until CR is pressed (at the OS level). 01017 01018 *******************************************************************************/ 01019 01020 static void testStdin() 01021 { 01022 int x; 01023 01024 // display a prompt - flush the output, since there is no 'newline' 01025 Stdout ("Enter a number: ") (); 01026 01027 // wait for <cr>, then convert input to integer. 01028 Stdin (x); 01029 } 01030 01031 01032 import std.regexp; 01033 01034 /******************************************************************************* 01035 01036 Use RegExp to scan words via a buffer. 01037 01038 *******************************************************************************/ 01039 01040 static void wordRegex (IBuffer buffer) 01041 { 01042 // create a new regex tokenizer for words 01043 RegexTokenizer rt = new RegexTokenizer (new RegExp(r"\w+", null)); 01044 01045 // create a token to hold tokenized output, and bind it to the buffer 01046 CompositeToken word = new CompositeToken (rt, buffer); 01047 01048 // read buffer a word at a time. Method next() returns false when no 01049 // more tokens are found 01050 while (word.next) 01051 Stdout (word) (CR); 01052 } 01053 01054 01055 01056 /******************************************************************************* 01057 01058 Use RegExp to scan file content via a buffer. Buffered scanning 01059 avoids loading the entire file into memory at one time. 01060 01061 *******************************************************************************/ 01062 01063 static void testFileRegex() 01064 { 01065 // open a file for reading 01066 FileConduit fc = new FileConduit ("test.txt"); 01067 01068 // extract words from file 01069 wordRegex (fc.createBuffer); 01070 } 01071 01072 01073 /******************************************************************************* 01074 01075 open an internet connection and scan home-page for words. 01076 01077 *******************************************************************************/ 01078 01079 static void testSocketRegex() 01080 { 01081 // create a socket and connect it to Walter's site 01082 SocketConduit sc = new SocketConduit(); 01083 sc.connect (new InternetAddress("www.digitalmars.com", 80)); 01084 01085 // construct a writer and bind it to the socket 01086 IWriter write = new DisplayWriter (sc); 01087 01088 // write HTTP request, and flush output socket 01089 write ("GET /d/intro.html HTTP/1.1\r\n" 01090 "Host: www.digitalmars.com\r\n\r\n") (); 01091 01092 // set read-timeout to 0.5 seconds (avoids stalling) 01093 sc.setTimeout (System.Interval.Millisec * 500); 01094 01095 // scan words out of home page 01096 wordRegex (sc.createBuffer); 01097 } 01098 01099 01100 /******************************************************************************* 01101 01102 Read lines from a file, and scan each line for words. This shows 01103 how to map the content of one buffer into another without copying 01104 any data. Unlikely to be a common activity. 01105 01106 *******************************************************************************/ 01107 01108 static void testLineRegex() 01109 { 01110 // open a file for reading 01111 FileConduit fc = new FileConduit ("test.txt"); 01112 01113 // create a token for lines, and map it onto the file buffer. 01114 CompositeToken line = new CompositeToken (Tokenizers.line, fc); 01115 01116 // create a seperate buffer for scanning within each line. We will 01117 // set the content for this buffer as we read each line. Note that 01118 // if we used the file buffer directly, then we'd continue reading 01119 // words right past the end of the line. This is because the file 01120 // buffer would just reload itself instead of halting at the line 01121 // termimator. 01122 Buffer rescan = new Buffer; 01123 01124 // scan all lines in the file, including the final one 01125 while (line.get) 01126 { 01127 // map our rescan buffer onto the line content 01128 rescan.setValidContent (line.toString); 01129 01130 // scan just this line for words 01131 wordRegex (rescan); 01132 } 01133 01134 } 01135 01136 /******************************************************************************* 01137 01138 Display the size of a file 01139 01140 *******************************************************************************/ 01141 01142 static void testFileSize() 01143 { 01144 FileProxy fp = new FileProxy ("test.txt"); 01145 01146 Stdout (fp.getPath) 01147 (" is ") 01148 (fp.getSize) 01149 (" bytes long") 01150 (CR); 01151 } 01152 01153 01154 /******************************************************************************* 01155 01156 list a set of files 01157 01158 *******************************************************************************/ 01159 01160 static void testFileList() 01161 { 01162 FileProxy proxy = new FileProxy (r"."); 01163 01164 foreach (FilePath path; proxy.toList()) 01165 Stdout.put(path).cr(); 01166 } 01167 01168 /******************************************************************************* 01169 01170 list a set of files 01171 01172 *******************************************************************************/ 01173 01174 static void testFilePath() 01175 { 01176 FilePath path = new FilePath (r"c:\1\2\3\4\abc.foo.bar"); 01177 01178 Stdout << path << CR; 01179 01180 Uri uri = path.toUri(); 01181 Stdout << uri.getScheme() << CR 01182 << uri.getHost() << CR 01183 << uri.getPath() << CR 01184 << uri.getPort() << CR 01185 << uri << CR; 01186 01187 uri = new Uri (uri.toString()); 01188 Stdout << uri.getScheme() << CR 01189 << uri.getHost() << CR 01190 << uri.getPath() << CR 01191 << uri.getPort() << CR 01192 << uri << CR; 01193 01194 path = new FilePath (uri); 01195 01196 Stdout << path << CR; 01197 } 01198 01199 01200 /******************************************************************************* 01201 01202 Construct a memory-mapped buffer upon a 200MB file. Note that we 01203 should close both the conduit and buffer when finished. 01204 01205 Note also that Win32 takes a while to close the initial file if 01206 it has just been created or resized. Subsequently opening the 01207 file as ReadWriteExising performs admirably. I imagine it's to 01208 do with spooling a gazillion dirty pages to the drive? 01209 01210 *******************************************************************************/ 01211 01212 void testMappedFile() 01213 { 01214 FileConduit conduit = new FileConduit ("test.bin", FileStyle.ReadWriteCreate); 01215 conduit.seek (200_000_000); 01216 conduit.truncate (); 01217 01218 MappedFile buffer = new MappedFile (conduit); 01219 buffer.setPosition (100_000_000); 01220 buffer.append ("test"); 01221 buffer.close (); 01222 01223 conduit.close (); 01224 } 01225 01226 /******************************************************************************* 01227 01228 Use Composite IO to read and write a data-set. See CompositeReader 01229 and CompositeWriter for more on this. 01230 01231 *******************************************************************************/ 01232 01233 static void testCompositeIO() 01234 { 01235 // define a serializable class (via interfaces) 01236 class Wumpus : IReadable, IWritable 01237 { 01238 private int x = 11, 01239 y = 112, 01240 z = 1024; 01241 01242 void write (IWriter output) 01243 { 01244 output (x) (y) (z); 01245 } 01246 01247 void read (IReader input) 01248 { 01249 input (x) (y) (z); 01250 } 01251 01252 } 01253 01254 // construct a Wumpus 01255 Wumpus wumpus = new Wumpus; 01256 01257 // open a file for IO 01258 FileConduit fc = new FileConduit ("random.bin", FileStyle.ReadWriteCreate); 01259 01260 // construct composite reader & writer upon the file, with binary IO 01261 IWriter write = new Writer (fc); 01262 IReader read = new Reader (fc); 01263 01264 // write the Wumpus (and flush it) 01265 write (wumpus) (); 01266 01267 // rewind to file start 01268 fc.seek (0); 01269 01270 // read Wumpus back again 01271 read (wumpus); 01272 01273 fc.close(); 01274 } 01275 01276 01277 01278 /******************************************************************************* 01279 01280 One can perform direct IO on a conduit, simply by mapping a Buffer 01281 onto a local array. No additional buffering takes place but readers, 01282 writers, and tokenizers can't tell the difference: they may all be 01283 used without issue. 01284 01285 This example uses the same direct-buffer for both reading & writing. 01286 However, seperate buffers may be used as appropriate. 01287 01288 *******************************************************************************/ 01289 01290 static void testDirectIO() 01291 { 01292 // open a file for IO 01293 auto FileConduit fc = new FileConduit ("random.bin", FileStyle.ReadWriteCreate); 01294 01295 // direct IO area (on the stack) 01296 ubyte[1024] content; 01297 01298 // map a buffer onto local content. State all of it is valid content. 01299 // There are other IBuffer methods, such as setValidContent(), which 01300 // stipulate how much data is really in the buffer. 01301 IBuffer direct = new Buffer(content, content.length); 01302 01303 // map our buffer onto the file 01304 direct.setConduit(fc); 01305 01306 // mess with the content[] ... 01307 // ... 01308 // ... 01309 // ... 01310 01311 // write directly from the local buffer (might use fc.flush() instead) 01312 fc.write (direct); 01313 01314 // rewind to file start 01315 fc.seek (0); 01316 01317 // make space for reading 01318 direct.clear(); 01319 01320 // read it all back in again 01321 int count = fc.read (direct); 01322 delete fc; 01323 01324 } 01325 01326 01327 /******************************************************************************* 01328 01329 *******************************************************************************/ 01330 01331 static void testUri() 01332 { 01333 MutableUri uri; 01334 01335 uri = new MutableUri ("ftp1://Me:My@a:21"); 01336 Stdout << uri << CR; 01337 01338 uri.parse ("http://a:8080/b/c/d;p?q=bar of soap#fragmented"); 01339 Stdout << uri << CR; 01340 01341 Stdin.wait(); 01342 01343 for (int i=10_000_000; i > 0; --i) 01344 uri.parse ("http://a:8080/b/c/d;p?q=bar of soap#fragmented"); 01345 } 01346 01347 01348 /****************************************************************************** 01349 ************************ SocketServer testing ********************************* 01350 *******************************************************************************/ 01351 01352 01353 01354 /******************************************************************************* 01355 01356 Test the http server by sending it a few thousand requests. Note 01357 that we don't use a reader or a writer here, though we could just 01358 as easily have done so. 01359 01360 Also note that (Gentoo) linux has a hard time scavenging sockets 01361 fast enough to complete more than around 6000 iterations. Without 01362 the appropriate guru incantations to make ulimit work as desired, 01363 we just limit the iterations to a more agreeable level. Testing 01364 under Win32 seems to be fine at the 100,000 iteration mark. 01365 01366 *******************************************************************************/ 01367 01368 void testClient () 01369 { 01370 Buffer buf = new Buffer(1024); 01371 InternetAddress addr = new InternetAddress("localhost", 80); 01372 01373 for (int i=10000; --i >= 0;) 01374 { 01375 // connect to the server 01376 SocketConduit socket = new SocketConduit (); 01377 socket.connect (addr); 01378 01379 // reset buffer for another go around 01380 buf.clear (); 01381 01382 // would need this if we were using Reader/Writer IO 01383 // buf.setConduit(socket); 01384 01385 // send a request. This will be serviced by our IProvider 01386 buf.append ("GET / HTTP/1.1\n\n"); 01387 socket.write (buf); 01388 01389 // wait for something to be returned (you can set a timeout) 01390 socket.read (buf); 01391 01392 // dump response to the console 01393 //Stdout.conduit.write (buf); 01394 01395 // when we close this socket, recycle it immediately! 01396 //socket.setLingerPeriod (0); 01397 01398 // attempt a graceful shutdown 01399 //socket.shutdown (); 01400 01401 // close and destroy socket (the latter will do both) 01402 socket.close (); 01403 delete socket; 01404 } 01405 } 01406 01407 01408 /******************************************************************************* 01409 01410 Create an http server with the given IProvider 01411 01412 *******************************************************************************/ 01413 01414 void testServer (IProvider provider) 01415 { 01416 // bind to port 80 on a local address 01417 InternetAddress addr = new InternetAddress (80); 01418 01419 // create a (1 thread) server using the IProvider to service requests 01420 HttpServer server = new HttpServer (provider, addr, 1); 01421 01422 // start listening for requests (but this thread does not listen) 01423 server.start (); 01424 01425 // pause for some console input 01426 Stdout.put("hit return to start the client test ...").flush(); 01427 Stdin.wait (); 01428 01429 // send a few thousand requests 01430 long time = System.getMillisecs; 01431 testClient (); 01432 Stdout.put (System.getMillisecs - time).cr(); 01433 } 01434 01435 01436 /******************************************************************************* 01437 01438 Declare a class for handling http requests. This one just simply 01439 returns a status page 01440 01441 *******************************************************************************/ 01442 01443 void testHttpServer () 01444 { 01445 class Provider : HttpProvider 01446 { 01447 void service (HttpRequest request, HttpResponse response) 01448 { 01449 response.sendError (HttpResponses.OK); 01450 } 01451 } 01452 01453 // create a new http-provider, and attach it to a server 01454 testServer (new Provider()); 01455 } 01456 01457 01458 /******************************************************************************* 01459 01460 Test the servlet wrapper. Point your Browser at http://127.0.0.1 01461 and optionally add a path, query params, etc ... 01462 01463 *******************************************************************************/ 01464 01465 void testServletEngine () 01466 { 01467 /*********************************************************************** 01468 01469 Return a file. Deliberately supports GET requests only. 01470 01471 ***********************************************************************/ 01472 01473 class FileServlet : MethodServlet 01474 { 01475 void doGet (IServletRequest request, IServletResponse response) 01476 { 01477 response.copyFile (request.getContext(), request.getPathInfo()); 01478 } 01479 } 01480 01481 01482 /*********************************************************************** 01483 01484 A whole bunch of diagnostic stuff, plus cookie return and 01485 rudimentary form processing. 01486 01487 ***********************************************************************/ 01488 01489 class MyServlet : Servlet 01490 { 01491 void service (IServletRequest request, IServletResponse response) 01492 { 01493 Uri uri = request.getUri(); 01494 01495 // log everything to the console 01496 Stdout ("------------------------") 01497 (CR) 01498 ("Uri: ") 01499 (uri) 01500 () 01501 ("------------------------") 01502 (CR) 01503 ("Headers:") 01504 (CR) 01505 (request.getHeaders) 01506 ("------------------------") 01507 (CR) 01508 ("Cookies:") 01509 (CR) 01510 (request.getCookies) 01511 ("------------------------") 01512 (CR) 01513 ("Parameters:") 01514 (CR) 01515 (request.getParameters) 01516 ("------------------------") 01517 (CR); 01518 01519 // display the Servlet environment 01520 Stdout ("encoding: ") 01521 (request.getCharacterEncoding) 01522 (CR) 01523 ("content length: ") (request.getContentLength) 01524 (CR) 01525 ("content type: ") (request.getContentType) 01526 (CR) 01527 ("protocol: ") (request.getProtocol) 01528 (CR) 01529 ("scheme: ") (uri.getScheme) 01530 (CR) 01531 ("method: ") (request.getMethod) 01532 (CR) 01533 ("host name: ") (request.getServerName) 01534 (CR) 01535 ("host port: ") (request.getServerPort) 01536 (CR) 01537 //.put("remote address: ").put(request.getRemoteAddress()).cr() 01538 //.put("remote host: ").put(request.getRemoteHost()).cr() 01539 ("path info: ") (request.getPathInfo) 01540 (CR) 01541 ("query: ") (uri.getQuery()) 01542 (CR) 01543 ("path: ") (uri.getPath()) 01544 (CR) 01545 ("context path: ") (request.getContextPath) 01546 (CR) 01547 (CR) 01548 (CR); 01549 01550 int i = request.getContentLength(); 01551 01552 if (i > 0) 01553 { 01554 byte[] content = new byte[i]; 01555 01556 request.getReader.getPostData (content); 01557 printf ("Content:\n>>%.*s<<\n\n\n", content); 01558 } 01559 01560 // send a cookie to the user-agent ... 01561 response.getCookies().add (new Cookie ("fu", "'bar of soap'")); 01562 01563 // send a form to the user-agent ... 01564 IWriter write = response.getWriter(); 01565 write ("<HTML><HEAD><TITLE>Form</TITLE></HEAD>") 01566 ("<BODY><FORM method=POST action=\"/context/test\">") 01567 ("Enter a POST parameter: ") 01568 ("<INPUT type=text name=\"name\"><P>") 01569 ("<INPUT type=hidden name=\"hidden\" value=\"test\"><P>") 01570 ("<INPUT type=submit>") 01571 ("<?FORM></BODY></HTML>") 01572 (CR); 01573 01574 } 01575 } 01576 01577 01578 // construct a servlet-provider 01579 ServletProvider sp = new ServletProvider(); 01580 01581 // map all html requests to our file servlet 01582 IRegisteredServlet files = sp.addServlet (new FileServlet(), "files"); 01583 sp.addMapping ("*.html", files); 01584 sp.addMapping ("*.htm", files); 01585 01586 // map all other request to our test servlet 01587 IRegisteredServlet test = sp.addServlet (new MyServlet(), "test"); 01588 sp.addMapping ("/", test); 01589 01590 // fire up a server 01591 testServer (sp); 01592 } 01593 01594 01595 /******************************************************************************* 01596 01597 Shows a variety of ways in which to access data returned from 01598 a client-side socket connection. 01599 01600 *******************************************************************************/ 01601 01602 void testHttpClient () 01603 { 01604 /*********************************************************************** 01605 01606 Bulk copy from input to Stdout 01607 01608 ***********************************************************************/ 01609 01610 void readBulk (IConduit conduit) 01611 { 01612 // stream directly to console 01613 Stdout.conduit.copy (conduit); 01614 } 01615 01616 /*********************************************************************** 01617 01618 Unwound version of the above, where we explicitly move 01619 data between endpoints using a buffer 01620 01621 ***********************************************************************/ 01622 01623 void readBulkExplicit (IConduit conduit) 01624 { 01625 // create a buffer for transferring content 01626 IBuffer buffer = conduit.createBuffer (); 01627 01628 // stream the data from file to stdout. This is probably as fast as 01629 // one can practically make operations of this type. 01630 while (conduit.read (buffer) != conduit.Eof) 01631 Stdout.conduit.write (buffer); 01632 01633 // ensure the writer actually wrote everything 01634 assert (Stdout.conduit.flush (buffer)); 01635 } 01636 01637 /*********************************************************************** 01638 01639 Read input a line at a time from the input. You can access 01640 the line content via method Token.toString() 01641 01642 ***********************************************************************/ 01643 01644 void readLines (IConduit conduit) 01645 { 01646 // create a Token and bind it to both the conduit and a line-tokenizer 01647 CompositeToken line = new CompositeToken (Tokenizers.line, conduit); 01648 01649 // read data a line at a time. Method next() returns false when no more 01650 // delimiters are found. Note there may be an unterminated line at eof 01651 while (line.get) 01652 Stdout (line) (CR); 01653 } 01654 01655 /*********************************************************************** 01656 01657 Read input a char at a time. This will read in big chunks 01658 of data from the input, but spit them out one character at 01659 a time. While this is a lot faster then reading one char 01660 at a time from the OS (the typical approach), this style 01661 of reading is not recommended. Instead, try the 'chunked' 01662 approach (below). 01663 01664 ***********************************************************************/ 01665 01666 void readChars (IConduit conduit) 01667 { 01668 // create a reader on the conduit 01669 Reader reader = new Reader (conduit); 01670 01671 // read a single character at a time, until we run out of them. 01672 // An exception will eventually be thrown because we're using 01673 // the 'formatted' data approach 01674 try { 01675 while (true) 01676 { 01677 char c; 01678 reader (c); 01679 Stdout (c); 01680 } 01681 } catch (IOException x){} 01682 } 01683 01684 /*********************************************************************** 01685 01686 Read big chunks of data, and process them as such. Each read 01687 operation will eat as much as there is from the input, up to 01688 the size limit of the buffer. 01689 01690 ***********************************************************************/ 01691 01692 void readChunks (IConduit conduit) 01693 { 01694 IBuffer buffer = new Buffer(1024); 01695 01696 while (conduit.read (buffer) != conduit.Eof) 01697 { 01698 Stdout (buffer.toString); 01699 buffer.clear (); 01700 } 01701 } 01702 01703 /*********************************************************************** 01704 01705 unwound version of the above, where we setup buffer space 01706 on the stack (instead of the heap). We need to explicitly 01707 ask the buffer how much data is actually available. One 01708 could use the return value from read() as the number of 01709 bytes available instead (in this particular case), or 01710 use buffer.toString() as in the above case 01711 01712 ***********************************************************************/ 01713 01714 void readChunksExplicit (IConduit conduit) 01715 { 01716 char[1024] content; 01717 01718 IBuffer buffer = new Buffer (content); 01719 01720 while (conduit.read (buffer) != conduit.Eof) 01721 { 01722 Stdout (content[0..buffer.readable()]); 01723 buffer.clear (); 01724 } 01725 } 01726 01727 01728 /*********************************************************************** 01729 01730 Open a web-site connection, and process the returned page 01731 01732 ***********************************************************************/ 01733 01734 // create a socket and connect it to Walter's site 01735 SocketConduit sc = new SocketConduit(); 01736 sc.connect (new InternetAddress("www.digitalmars.com", 80)); 01737 01738 // construct a writer and bind it to the socket 01739 IWriter w = new FlushWriter (sc); 01740 01741 // send HTTP request 01742 w.put ("GET /d/intro.html HTTP/1.1") 01743 .cr () 01744 .put ("Host: www.digitalmars.com") 01745 .cr () 01746 .cr (); 01747 01748 // set read-timeout to 1 second (avoids stalling for ever!) 01749 sc.setTimeout (System.Interval.Second); 01750 01751 //readBulk (sc); 01752 //readBulkExplicit(sc); 01753 //readLines(sc); 01754 //readChars(sc); 01755 //readChunks(sc); 01756 readChunksExplicit(sc); 01757 01758 // flush output 01759 Stdout (); 01760 } 01761 01762 01763 /******************************************************************************* 01764 01765 Extract client-side headers from an HTTP reply 01766 01767 *******************************************************************************/ 01768 01769 void testHttpClient2 () 01770 { 01771 // create a socket and connect it to Walter's site 01772 SocketConduit sc = new SocketConduit; 01773 sc.connect (new InternetAddress("www.digitalmars.com", 80)); 01774 01775 // construct a writer and bind it to the socket 01776 IWriter w = new FlushWriter (sc); 01777 01778 // send HTTP request 01779 w.put ("GET /d/intro.html HTTP/1.1") 01780 .cr () 01781 .put ("Host: www.digitalmars.com") 01782 .cr () 01783 .cr (); 01784 01785 // set read-timeout to 1 second (avoids stalling for ever!) 01786 sc.setTimeout (System.Interval.Second); 01787 01788 // create an input buffer 01789 IBuffer buffer = sc.createBuffer; 01790 01791 // extract all headers 01792 HttpHeaders headers = new HttpHeaders; 01793 headers.parse (buffer); 01794 01795 // display parsed headers -- these should match HttpHeader.HttpHeaders 01796 foreach (HeaderElement header; headers) 01797 Stdout.put (header.name.value) 01798 .put (header.value) 01799 .cr (); 01800 01801 // display remaining content 01802 while (sc.read (buffer) != sc.Eof) 01803 { 01804 Stdout (buffer.toString); 01805 buffer.clear (); 01806 } 01807 Stdout (); 01808 } 01809 01810 /******************************************************************************* 01811 01812 Poke an HTTP server, using HttpClient. 01813 01814 *******************************************************************************/ 01815 01816 void testHttpClient3() 01817 { 01818 // create client for a GET request 01819 auto HttpClient client = new HttpClient (HttpClient.Get, "http://www.digitalmars.com/d/intro.html"); 01820 01821 // setup a Host header 01822 client.getRequestHeaders.add (HttpHeader.Host, client.getUri.getHost); 01823 01824 // make request 01825 IBuffer b = client.open (); 01826 01827 // check return status for validity 01828 if (client.isResponseOK) 01829 { 01830 // extract content length (be aware of -1 return, for no header) 01831 int length = client.getResponseHeaders.getInt (HttpHeader.ContentLength); 01832 if (length < 0) 01833 length = int.max; 01834 01835 // display all returned headers 01836 Stdout.put (client.getResponseHeaders); 01837 01838 // display remaining content 01839 client.read (delegate (char[] c){Stdout.put(c);}, length); 01840 Stdout (); 01841 } 01842 else 01843 Stderr.put (client.getResponse); 01844 } 01845 01846 01847 01848 01849 /****************************************************************************** 01850 **************************** Cache testing ************************************ 01851 *******************************************************************************/ 01852 01853 01854 01855 /******************************************************************************* 01856 01857 01858 *******************************************************************************/ 01859 01860 void testPlainCache() 01861 { 01862 PlainCache cache = new PlainCache (2); 01863 01864 cache.put ("a", new Payload); 01865 cache.put ("b", new Payload); 01866 cache.put ("c", new Payload); 01867 cache.put ("c", new Payload); 01868 01869 cache.extract ("b"); 01870 assert (cache.get("a")); 01871 assert (cache.get("c")); 01872 assert (cache.get("b") is null); 01873 } 01874 01875 /******************************************************************************* 01876 01877 QueuedCache maintains a linked list of items, in addition to a 01878 hashmap. Any reference to an item places it at the list head, 01879 resulting in the LRU items always being left at the tail. When 01880 the list becomes full, tail items are dropped and their places 01881 reused. 01882 01883 This is great for keeping commonly accessed items around, while 01884 limiting the amount of memory used. 01885 01886 Typically, the queue size would be set in the hundreds (perhaps 01887 thousands) but we just use 2 for testing purposes. 01888 01889 *******************************************************************************/ 01890 01891 void testQueuedCache() 01892 { 01893 QueuedCache cache = new QueuedCache (2); 01894 01895 cache.put ("a", new Payload); 01896 cache.put ("b", new Payload); 01897 cache.put ("c", new Payload); 01898 cache.put ("c", new Payload); 01899 01900 assert (cache.get("a") is null); 01901 assert (cache.get("c")); 01902 } 01903 01904 /******************************************************************************* 01905 01906 Stuff some data into a FileBucket, and pull it out again. 01907 01908 *******************************************************************************/ 01909 01910 void testFileBucket() 01911 { 01912 char[] text = "this is a test"; 01913 01914 FileBucket bucket = new FileBucket (new FilePath ("bucket.bin"), FileBucket.HalfK, 0); 01915 01916 // insert some data, and retrieve it again 01917 bucket.put ("a", text); 01918 char[] b = cast(char[]) bucket.get ("a"); 01919 01920 assert (b == text); 01921 bucket.close(); 01922 } 01923 01924 01925 /******************************************************************************* 01926 01927 Use a combination of QueuedCache and FileBucket to spill LRU 01928 cache entries onto the hard-drive, and then recover them intact. 01929 01930 This demonstrates what one can do with the IPickle notion. 01931 01932 *******************************************************************************/ 01933 01934 void testVirtualCache() 01935 { 01936 FileBucket bucket = new FileBucket (new FilePath ("bucket.bin"), FileBucket.HalfK); 01937 VirtualCache cache = new VirtualCache (bucket, 2); 01938 PickleRegistry.enroll (new Payload); 01939 01940 cache.put ("a", new Payload); 01941 cache.put ("b", new Payload); 01942 cache.put ("c", new Payload); 01943 01944 assert (cache.get("a")); 01945 assert (cache.get("c")); 01946 assert (cache.get("b")); 01947 bucket.close(); 01948 } 01949 01950 /******************************************************************************* 01951 01952 01953 *******************************************************************************/ 01954 01955 void testProtocol() 01956 { 01957 class Protocol : Payload 01958 { 01959 char[] x; 01960 int y = 10; 01961 bool z = true; 01962 01963 this () 01964 { 01965 x = "fred"; 01966 } 01967 01968 static this() 01969 { 01970 PickleRegistry.enroll(new Protocol); 01971 } 01972 01973 void write (IWriter w) 01974 { 01975 super.write (w); 01976 w.put (x) 01977 .put (y) 01978 .put (z); 01979 } 01980 01981 void read (IReader r) 01982 { 01983 super.read (r); 01984 r.get (x) 01985 .get (y) 01986 .get (z); 01987 01988 assert (x == "fred"); 01989 assert (y == 10); 01990 assert (z == true); 01991 } 01992 01993 Payload create () 01994 { 01995 return new Protocol; 01996 } 01997 01998 char[] getGuid () 01999 { 02000 return this.classinfo.name; 02001 } 02002 } 02003 02004 Protocol p = new Protocol; 02005 02006 Buffer b = new Buffer (1024); 02007 ProtocolWriter w = new ProtocolWriter (b); 02008 ProtocolReader r = new ProtocolReader (b); 02009 02010 w.put (w.Command.Exception, "mychannel", p); 02011 02012 ubyte cmd; 02013 char[] channel, 02014 element; 02015 02016 p = cast(Protocol) r.getPayload (channel, element, cmd); 02017 } 02018 02019 02020 /******************************************************************************* 02021 02022 02023 *******************************************************************************/ 02024 02025 version (Isolated){} 02026 else 02027 { 02028 void testRollingFileLog() 02029 { 02030 Logger l = Logger.getLogger ("test"); 02031 l.addAppender (new RollingFileAppender (new FilePath (r"e:\test.log"), 3, 1024, new DateLayout)); 02032 02033 for (int i=100; --i;) 02034 l.error ("weqwer er wer werqwer wer wer wer wr wqrwe qrw rwe rwqerw"); 02035 } 02036 } 02037 02038 02039 02040 /****************************************************************************** 02041 **************************** Cluster testing ********************************** 02042 *******************************************************************************/ 02043 02044 02045 02046 /******************************************************************************* 02047 02048 Join a socket to a multicast group, and send the group a packet. 02049 02050 *******************************************************************************/ 02051 02052 void testMulticast() 02053 { 02054 class MyListener : SocketListener 02055 { 02056 this (ISocketReader reader, IBuffer buffer) 02057 { 02058 super (reader, buffer); 02059 } 02060 02061 void notify (IBuffer buffer) 02062 { 02063 printf ("listener received %d bytes\n", buffer.readable()); 02064 } 02065 02066 void exception (char[] msg) 02067 { 02068 printf ("listener error: %.*s\n", msg); 02069 } 02070 } 02071 02072 //auto MulticastSocket ms = new MulticastSocket (); 02073 MulticastSocket ms = new MulticastSocket (); 02074 InternetAddress ia = new InternetAddress ("226.1.1.1", 4444); 02075 02076 ms.join (ia); 02077 MyListener s = new MyListener (ms, new Buffer (2000)); 02078 s.start (); 02079 02080 Stdin.wait (); 02081 //s.pause (); 02082 //s.resume (); 02083 02084 byte[1000] xx; 02085 Buffer b = new Buffer (xx, xx.length); 02086 02087 ms.write (b, ia); 02088 Stdin.wait (); 02089 //s.cancel (); 02090 } 02091 02092 /******************************************************************************* 02093 02094 *******************************************************************************/ 02095 02096 void testClusterCache() 02097 { 02098 //ClusterServer cs = new ClusterServer (new InternetAddress(4567), 1); 02099 //cs.start (); 02100 02101 //auto FileConduit config = new FileConduit ("cluster.properties"); 02102 //Cluster cluster = new Cluster (logger, config); 02103 Cluster cluster = new Cluster (logger, 4567); 02104 02105 //NetworkCache cc = new NetworkCombo (cluster, "myChannel", new PlainCache); 02106 NetworkCache cc = new NetworkCache (cluster, "myChannel"); 02107 02108 InvalidatorPayload p = new InvalidatorPayload; 02109 02110 cc.put ("key", p); 02111 // cc.invalidate ("key"); 02112 for (int i=100_000; i; --i) 02113 { 02114 // p.setText ("fubar"); 02115 // cc.put ("key", p); 02116 // cc.invalidate ("key"); 02117 IPayload p = cc.get ("key"); 02118 // if ((i & 0x3f) == 0) 02119 // System.sleep (System.Interval.Second); 02120 /* 02121 p = cast(InvalidatorPayload) cc.get ("key"); 02122 assert (p); 02123 assert (p.getText == "fubar"); 02124 02125 cc.invalidate ("key"); 02126 p = cast(InvalidatorPayload) cc.get ("key"); 02127 */ 02128 } 02129 //assert (p is null); 02130 02131 // cc.invalidate ("key"); 02132 02133 //Stdin.wait (); 02134 } 02135 02136 02137 /******************************************************************************* 02138 02139 *******************************************************************************/ 02140 02141 void testClusterQueue() 02142 { 02143 class Listen : IEventListener 02144 { 02145 void notify (IEvent event, IPayload payload) 02146 { 02147 printf ("recieved queue entry from channel '%.*s'\n", event.getChannel.getName); 02148 } 02149 } 02150 02151 //ClusterServer cs = new ClusterServer (new InternetAddress(4567), 1); 02152 //cs.start (); 02153 02154 Cluster cluster = new Cluster (logger, 4567); 02155 NetworkQueue queue = new NetworkQueue (cluster, "queue.channel"); 02156 02157 queue.createConsumer (new Listen); 02158 queue.put (new InvalidatorPayload); 02159 queue.put (new InvalidatorPayload); 02160 02161 Stdin.wait (); 02162 } 02163 02164 02165 /******************************************************************************* 02166 02167 *******************************************************************************/ 02168 02169 void testInvalidatee() 02170 { 02171 ICluster c = new Cluster (logger); 02172 02173 CacheInvalidatee dst = new CacheInvalidatee (c, "abc", new PlainCache); 02174 CacheInvalidator src = new CacheInvalidator (c, "abc"); 02175 02176 src.invalidate ("key1"); 02177 02178 Stdin.wait (); 02179 } 02180 02181 02182 /******************************************************************************* 02183 02184 02185 *******************************************************************************/ 02186 02187 void testClusterServer() 02188 { 02189 ClusterServer cs = new ClusterServer (new InternetAddress(81), 1); 02190 SocketConduit sc = new SocketConduit (); 02191 cs.start(); 02192 02193 sc.connect (new InternetAddress ("127.0.0.1", 81)); 02194 Stdin.wait (); 02195 } 02196 02197 02198 /******************************************************************************* 02199 02200 02201 *******************************************************************************/ 02202 02203 02204 void testClusterMessage() 02205 { 02206 class MessageListener : IEventListener 02207 { 02208 void notify (IEvent event, IPayload payload) 02209 { 02210 IMessage message = cast(IMessage) payload; 02211 02212 printf ("Replying to message\n"); 02213 event.reply (message.getReply, new InvalidatorPayload); 02214 } 02215 } 02216 02217 class ReplyListener : IEventListener 02218 { 02219 void notify (IEvent event, IPayload payload) 02220 { 02221 printf ("Received reply\n"); 02222 } 02223 } 02224 02225 //ClusterServer cs = new ClusterServer (new InternetAddress(4567), 1); 02226 //cs.start (); 02227 02228 // open the cluster 02229 Cluster cluster = new Cluster (logger, 4567); 02230 02231 // open up a message channel 02232 NetworkMessage msg = new NetworkMessage (cluster, "message.channel", new ReplyListener); 02233 02234 // setup a listener to receive message (could do this earlier) 02235 msg.createConsumer (new MessageListener); 02236 02237 // toss a message out to the cluster 02238 msg.put (new NullMessage); 02239 02240 // wait for traffic to pass by 02241 Stdin.wait (); 02242 } 02243 02244 02245 /******************************************************************************* 02246 02247 02248 *******************************************************************************/ 02249 02250 void testCacheLoader() 02251 { 02252 class CacheLoader : ICacheLoader 02253 { 02254 bool test (IPayload p) 02255 { 02256 return false; 02257 } 02258 02259 IPayload load (char[] key, long time) 02260 { 02261 printf ("loading local cache instance\n"); 02262 return new NullMessage; 02263 } 02264 } 02265 02266 IMutableCache mc = new PlainCache; 02267 ICache c = mc.bind (new CacheLoader); 02268 02269 c.get ("abcde"); 02270 } 02271 02272 02273 /******************************************************************************* 02274 02275 02276 *******************************************************************************/ 02277 02278 void testRemoteCacheLoader() 02279 { 02280 class RemoteCacheLoader : Payload, IRemoteCacheLoader 02281 { 02282 bool test (IPayload p) 02283 { 02284 return false; 02285 } 02286 02287 IPayload load (char[] key, long time) 02288 { 02289 printf ("loading remote cache instance\n"); 02290 return new NullMessage; 02291 } 02292 02293 /********************************************************************** 02294 02295 Recover the timestamp from the provided reader 02296 02297 **********************************************************************/ 02298 02299 void read (IReader reader) 02300 { 02301 super.read (reader); 02302 } 02303 02304 /********************************************************************** 02305 02306 Emit our timestamp to the provided writer 02307 02308 **********************************************************************/ 02309 02310 void write (IWriter writer) 02311 { 02312 super.write (writer); 02313 } 02314 02315 /*********************************************************************** 02316 02317 Create a new instance of a payload, and populate it via 02318 read() using the specified reader 02319 02320 ***********************************************************************/ 02321 02322 Object create (IReader reader) 02323 { 02324 Payload r = new RemoteCacheLoader; 02325 r.read (reader); 02326 return r; 02327 } 02328 02329 /********************************************************************** 02330 02331 Return the guid for this payload. This should be unique 02332 per payload class, if said class is used in conjunction 02333 with the clustering facilities. Inspected by the Pickle 02334 utilitiy classes. 02335 02336 **********************************************************************/ 02337 02338 char[] getGuid () 02339 { 02340 return this.classinfo.name; 02341 } 02342 02343 02344 uint pause (uint wait) 02345 { 02346 return 100_000; 02347 } 02348 } 02349 02350 Cluster cluster = new Cluster (logger, 4567); 02351 NetworkCache nc = new NetworkCache (cluster, "my.channel"); 02352 IRemoteCacheLoader cl = new RemoteCacheLoader; 02353 ICache c = nc.bind (cl); 02354 02355 c.get ("abcde"); 02356 } 02357 02358 version (Isolated){} 02359 else 02360 { 02361 /******************************************************************************* 02362 02363 02364 *******************************************************************************/ 02365 02366 void testDecoder () 02367 { 02368 IWriter w = new Writer (new Buffer(100)); 02369 IReader r = new Reader (w.getBuffer()); 02370 r.setAllocator (new BufferAllocator); 02371 02372 UConverter cvt = new UConverter("utf16"); 02373 w.setEncoder (new StringEncoder16 (cvt)); 02374 r.setDecoder (new StringDecoder16 (cvt)); 02375 02376 UString ss = new UString ("hello"); 02377 02378 w (ss); 02379 r (ss); 02380 02381 Stdout.setEncoder (new StringEncoder16("utf8")); 02382 Stdout (ss) (CR); 02383 } 02384 02385 /******************************************************************************* 02386 02387 02388 *******************************************************************************/ 02389 02390 void testEncoder () 02391 { 02392 FileConduit fc = new FileConduit("foo.txt", FileStyle.ReadWriteCreate); 02393 IWriter w = new DisplayWriter(fc); 02394 w.setEncoder (new StringEncoder8 ("utf8")); 02395 w.setEncoder (new StringEncoder16 ("utf8")); 02396 w.setEncoder (new StringEncoder32 ("utf8")); 02397 w ("<?xml version='1.0'?>") ("<element") (' ') ("/>") (CR); 02398 } 02399 02400 /******************************************************************************* 02401 02402 check the Regex stuff is hooked up 02403 02404 *******************************************************************************/ 02405 02406 void testRegex () 02407 { 02408 wchar[] fields[10]; 02409 02410 Stdout.setEncoder (new StringEncoder16 ("utf8")); 02411 02412 URegex r = new URegex ("[0-9]+", URegex.Flag.CaseInsensitive); 02413 r.setText (new UString ("123abc456def789")); 02414 02415 for (int i = r.split(fields); i-- > 0;) 02416 { 02417 wchar[] x = fields[i]; 02418 Stdout.putw(x) (CR); 02419 } 02420 } 02421 02422 void testRegex1 () 02423 { 02424 Stdout.setEncoder (new StringEncoder16 ("utf8")); 02425 02426 URegex r = new URegex ("(1).*(abc).*(789)", URegex.Flag.CaseInsensitive); 02427 r.setText (new UString ("123abc456def789")); 02428 02429 if (r.next) 02430 with (r.groups()) 02431 { 02432 Stdout .putw(g0) (' ') .putw(g1) (' ') .putw(g2) (' ') .putw(g3) (CR); 02433 } 02434 } 02435 } 02436 02437 /******************************************************************************* 02438 02439 02440 *******************************************************************************/ 02441 02442 void testTextWriter () 02443 { 02444 TextWriter output = new TextWriter (Stdout.getBuffer(), ", "); 02445 02446 ubyte b = 129; 02447 uint ui = uint.max; 02448 int i = -3; 02449 02450 output.setRadix (output.Radix.Decimal); 02451 output (b) (ui) (i) ("hello") ("test") (CR); 02452 } 02453 02454 /******************************************************************************* 02455 02456 Callback for dtoa allocation function 02457 02458 *******************************************************************************/ 02459 /+ 02460 extern (C) 02461 { 02462 int printf (char *format, ...) 02463 { 02464 Stderr ("invalid call to printf")(CR); 02465 return 0; 02466 } 02467 } 02468 +/ 02469 02470 /******************************************************************************* 02471 02472 02473 *******************************************************************************/ 02474 /+ 02475 private import mango.format.DGDouble; 02476 02477 void testConvert () 02478 { 02479 char[200] s; 02480 char[5] g; 02481 char *zz; 02482 static uint[] ff = [1, 2, 3, 4]; 02483 char[] num = "0.12345678+1"; 02484 02485 02486 double x = Double.parse (num); 02487 double y = std.c.stdlib.strtold (num, &zz); 02488 double z = DGDouble.parse (num); 02489 02490 02491 Stdout (Double.format (s, x, 20)) (CR); 02492 Stdout (Double.format (s, y, 20)) (CR); 02493 Stdout (Double.format (s, z, 20)) (CR); 02494 printf ("%.20lf\n", x); 02495 printf ("%.20lf\n", y); 02496 printf ("%.20lf\n", z); 02497 printf ("%.*s\n", DGDouble.format (s, x, 4)); 02498 printf ("%.*s\n", DGDouble.format (s, z, 6, true, 0)); 02499 } 02500 +/ 02501 02502 /******************************************************************************* 02503 02504 02505 *******************************************************************************/ 02506 02507 int main(char[][] args) 02508 { 02509 BasicConfigurator.configure (); 02510 //PropertyConfigurator.configure ("log.properties"); 02511 logger = Logger.getLogger ("mango.unittest"); 02512 //logger.setLevel (logger.Level.Error); 02513 //logger.addAppender (new FileAppender ("log.txt", new DateLayout)); 02514 //logger.addAppender (new ConsoleAppender (new DateLayout)); 02515 //logger.addAppender (new DebugAppender (new SimpleTimerLayout)); 02516 02517 try { 02518 //testDisplay(); 02519 //testDecoder(); 02520 //testTextWriter(); 02521 //testHashMap(); 02522 //testRemoteCacheLoader(); 02523 //testCacheLoader(); 02524 //testProtocol(); 02525 //testClusterMessage(); 02526 //testRollingFileLog(); 02527 //testClusterCache(); 02528 //testClusterQueue(); 02529 //testClusterServer(); 02530 //testInvalidatee(); 02531 //testMulticast(); 02532 02533 //testAppend(); 02534 //testFile4(); 02535 //testClassSerialization(); 02536 //testFormat(); 02537 //testLayout(); 02538 //testFileSize(); 02539 //testFilePath(); 02540 //testFileList(); 02541 //testScanFiles(); 02542 //testFile1(); 02543 //testFile5(); 02544 //testToken1(); 02545 //testToken2(); 02546 //testColumn(); 02547 //testSocket(); 02548 //testStdin(); 02549 //testBuffer(); 02550 //testToken3(); 02551 //testFileRegex(); 02552 //testLineRegex(); 02553 //testSocketRegex(); 02554 //testRandomAccess(); 02555 //testCompositeIO(); 02556 //testDirectIO(); 02557 //testHttpServer(); 02558 //testServletEngine(); 02559 //testUri(); 02560 //testHttpClient(); 02561 //testHttpClient2(); 02562 //testHttpClient3(); 02563 //testQueuedCache(); 02564 //testFileBucket(); 02565 //testScanFiles(); 02566 //testVirtualCache(); 02567 //testQueuedCache(); 02568 //testPlainCache(); 02569 //testMappedFile(); 02570 //testEncoder(); 02571 //testClassIO(); 02572 //testConvert(); 02573 //testRegex(); 02574 //testRegex1(); 02575 logger.info ("Done"); 02576 } catch (Object x) 02577 { 02578 logger.fatal (x.toString); 02579 } 02580 02581 return 0; 02582 } 02583