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