Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

Conduit.d

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003         @file Conduit.d
00004         
00005         Copyright (c) 2004 Kris Bell
00006         
00007         This software is provided 'as-is', without any express or implied
00008         warranty. In no event will the authors be held liable for damages
00009         of any kind arising from the use of this software.
00010         
00011         Permission is hereby granted to anyone to use this software for any 
00012         purpose, including commercial applications, and to alter it and/or 
00013         redistribute it freely, subject to the following restrictions:
00014         
00015         1. The origin of this software must not be misrepresented; you must 
00016            not claim that you wrote the original software. If you use this 
00017            software in a product, an acknowledgment within documentation of 
00018            said product would be appreciated but is not required.
00019 
00020         2. Altered source versions must be plainly marked as such, and must 
00021            not be misrepresented as being the original software.
00022 
00023         3. This notice may not be removed or altered from any distribution
00024            of the source.
00025 
00026         4. Derivative works are permitted, but they must carry this notice
00027            in full and credit the original source.
00028 
00029 
00030                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00031 
00032 
00033         @version        Initial version, March 2004      
00034         @author         Kris
00035 
00036 
00037 *******************************************************************************/
00038 
00039 module mango.io.Conduit;
00040 
00041 private import  mango.io.Resource,
00042                 mango.io.Exception,
00043                 mango.io.ConduitStyle;
00044 
00045 private import  mango.io.model.IBuffer;
00046 
00047 public  import  mango.io.model.IConduit;
00048 
00049 /*******************************************************************************
00050 
00051         Conduit abstract base-class, implementing interface IConduit. 
00052         Only the conduit-specific read, write, and buffer-factory 
00053         need to be implemented for a concrete conduit implementation. 
00054         See FileConduit for an example.
00055        
00056         Conduits provide virtualized access to external content, and 
00057         represent things like files or Internet connections. Conduits 
00058         are modelled by mango.io.model.IConduit, and implemented via 
00059         classes FileConduit and SocketConduit. 
00060         
00061         Additional kinds of conduit are easy to construct: one either 
00062         subclasses mango.io.Conduit, or implements mango.io.model.IConduit. 
00063         A conduit typically reads and writes from/to an IBuffer in large 
00064         chunks, typically the entire buffer. Alternatively, one can invoke 
00065         read(dst[]) and/or write(src[]) directly.
00066 
00067 *******************************************************************************/
00068 
00069 class Conduit : Resource, IConduit
00070 {
00071         private ConduitStyle    style;
00072         private IConduitSource  input;
00073         private IConduitSink    output;
00074         private bool            seekable;
00075 
00076         /***********************************************************************
00077         
00078                 Construct a conduit with the given style and seek abilities. 
00079                 Conduits are either seekable or non-seekable.
00080 
00081         ***********************************************************************/
00082 
00083         this (ConduitStyle style, bool seekable)
00084         {
00085                 input = this;
00086                 output = this;
00087                 this.style = style;
00088                 this.seekable = seekable;
00089         }
00090 
00091         /***********************************************************************
00092         
00093                 Create a Buffer of a conduit-specific size
00094 
00095         ***********************************************************************/
00096 
00097         abstract IBuffer createBuffer (); 
00098                      
00099         /***********************************************************************
00100         
00101                 conduit-specific reader
00102 
00103         ***********************************************************************/
00104 
00105         abstract int read (void[] dst);               
00106 
00107         /***********************************************************************
00108         
00109                 conduit-specific writer
00110 
00111         ***********************************************************************/
00112 
00113         abstract int write (void[] src);               
00114 
00115         /***********************************************************************
00116         
00117                 Method to close the filters. This is invoked from the 
00118                 Resource base-class when the resource is being closed.
00119                 You should ensure that a subclass invokes this as part
00120                 of its closure mechanics.
00121 
00122         ***********************************************************************/
00123 
00124         protected override void closure ()
00125         {       
00126                 input.unbind ();
00127                 output.unbind ();
00128         }    
00129                    
00130         /***********************************************************************
00131         
00132                 Please refer to IConduit.attach for details
00133 
00134         ***********************************************************************/
00135 
00136         void attach (IConduitSource input)
00137         {
00138                 input.bind (this.input);
00139                 this.input = input;
00140         }
00141 
00142         /***********************************************************************
00143         
00144                 Please refer to IConduit.attach for details
00145 
00146         ***********************************************************************/
00147 
00148         void attach (IConduitSink output)
00149         {
00150                 output.bind (this.output);
00151                 this.output = output;
00152         }
00153 
00154         /***********************************************************************
00155         
00156         ***********************************************************************/
00157 
00158         protected void bind (IConduitSink next)
00159         {
00160         }
00161                               
00162         /***********************************************************************
00163         
00164         ***********************************************************************/
00165 
00166         protected void bind (IConduitSource next)
00167         {
00168         }
00169                               
00170         /***********************************************************************
00171         
00172         ***********************************************************************/
00173 
00174         protected void unbind ()
00175         {
00176         }
00177 
00178         /***********************************************************************
00179          
00180                 read from conduit into a target buffer
00181 
00182         ***********************************************************************/
00183 
00184         int read (IBuffer target)
00185         in {
00186            assert (target);
00187            }
00188         body
00189         {
00190                 return target.write (&input.read);
00191         }              
00192 
00193         /***********************************************************************
00194         
00195                 write to conduit from a source buffer
00196 
00197         ***********************************************************************/
00198 
00199         int write (IBuffer source)
00200         in {
00201            assert (source);
00202            }
00203         body
00204         {
00205                 int count = source.read (&output.write);
00206 
00207                 // if we didn't write everything, move remaining content
00208                 // to front of buffer for a subsequent write
00209                 source.compress ();
00210                 return count;
00211         }              
00212 
00213         /***********************************************************************
00214         
00215                 Returns true if this conduit is seekable (whether it 
00216                 implements ISeekable)
00217 
00218         ***********************************************************************/
00219 
00220         bool isSeekable ()
00221         {
00222                 return seekable;
00223         }               
00224 
00225         /***********************************************************************
00226         
00227                 Returns true is this conduit can be read from
00228 
00229         ***********************************************************************/
00230 
00231         bool isReadable ()
00232         {
00233                 return (style.access & ConduitStyle.Access.Read) != 0;
00234         }               
00235 
00236         /***********************************************************************
00237         
00238                 Returns true if this conduit can be written to
00239 
00240         ***********************************************************************/
00241 
00242         bool isWritable ()
00243         {
00244                 return (style.access & ConduitStyle.Access.Write) != 0;
00245         }               
00246 
00247         /***********************************************************************
00248 
00249                 Transfer the content of another conduit to this one. Returns 
00250                 a reference to this class, and throws IOException on failure.
00251         
00252         ***********************************************************************/
00253 
00254         IConduit copy (IConduit source)
00255         {
00256                 IBuffer buffer = createBuffer;
00257 
00258                 while (source.read (buffer) != Eof)
00259                        if (write (buffer) == Eof)
00260                            throw new IOException ("Eof while copying conduit");
00261 
00262                 // flush any remains into the target
00263                 buffer.flush ();
00264                 return this;
00265         }               
00266 
00267         /***********************************************************************
00268         
00269                 Return the style used when creating this conduit
00270 
00271         ***********************************************************************/
00272 
00273         ConduitStyle getStyle ()
00274         {
00275                 return style;
00276         }    
00277 }
00278 
00279 
00280 
00281 /*******************************************************************************
00282         
00283         Defines an input filter base-class. The filter is invoked
00284         via its read(void[]) method whenever a block of content is 
00285         being read; the void[] array represents content destination.
00286         The filter should return the number of bytes it has actually
00287         produced: less than or equal to the length of the provided 
00288         array. 
00289 
00290         Filters are chained together such that the last filter added
00291         is the first one invoked. It is the responsibility of each
00292         filter to invoke the next link in the chain; for example:
00293 
00294         @code
00295         class MungingInputFilter : FilterInput
00296         {
00297                 int read (void[] dst)
00298                 {
00299                         // read the next X bytes
00300                         int count = next.read (dst);
00301 
00302                         // set everything to '*' !
00303                         dst[0..count] = '*';
00304 
00305                         // say how many we read
00306                         return count;
00307                 }
00308         }
00309         @endcode
00310 
00311         Notice how this filter invokes the 'next' instance before 
00312         munging the content ... the far end of the chain is where
00313         the original IConduit reader is attached, so it will get
00314         invoked eventually assuming each filter invokes 'next'. 
00315         If the next reader fails it will return IConduit.Eof, as
00316         should your filter (or throw an IOException). From a client 
00317         perspective, filters are attached like this:
00318 
00319         @code
00320         FileConduit fc = new FileConduit (...);
00321 
00322         fc.attach (new ZipInputFilter);
00323         fc.attach (new MungingInputFilter);
00324         @endcode
00325 
00326         Again, the last filter attached is the first one invoked 
00327         when a block of content is actually read. Each filter has
00328         two additional methods that it may use to control behavior:
00329 
00330         @code
00331         class FilterInput : IFilterInput
00332         {
00333                 protected IFilterInput next;
00334 
00335                 void bind (IFilterInput next)
00336                 {
00337                         this.next = next;
00338                 }
00339 
00340                 void unbind ()
00341                 {
00342                 }
00343         }
00344         @endcode
00345 
00346         The first method is invoked when the filter is attached to a 
00347         conduit, while the second is invoked just before the conduit 
00348         is closed. Both of these may be overridden by the filter for
00349         whatever purpose desired.
00350 
00351         Note that an input filter can choose to sidestep reading from 
00352         the conduit (per the usual case), and produce its input from 
00353         somewhere else entirely. This mechanism supports the notion
00354         of 'piping' between multiple conduits, or between a conduit 
00355         and something else entirely; it's a bridging mechanism.
00356 
00357 *******************************************************************************/
00358 
00359 class ConduitSource : IConduitSource
00360 {
00361         protected IConduitSource next;
00362 
00363         /***********************************************************************
00364         
00365         ***********************************************************************/
00366 
00367         abstract int read (void[] dst);
00368 
00369         /***********************************************************************
00370         
00371         ***********************************************************************/
00372 
00373         protected void bind (IConduitSource next)
00374         {
00375                 //printf ("bind input\n");
00376                 this.next = next;
00377         }
00378 
00379         /***********************************************************************
00380         
00381         ***********************************************************************/
00382 
00383         protected void unbind ()
00384         {
00385                 //printf ("unbind input\n");
00386                 next.unbind ();
00387         }
00388 }
00389 
00390 
00391 /*******************************************************************************
00392 
00393         Defines an output filter base-class. The filter is invoked
00394         via its write(void[]) method whenever a block of content is 
00395         being written; the void[] array supplies writeable content.
00396         The filter should return the number of bytes it has actually
00397         consumed: less than or equal to the length of the provided 
00398         array. 
00399 
00400         Filters are chained together such that the last filter added
00401         is the first one invoked. It is the responsibility of each
00402         filter to invoke the next link in the chain; for example:
00403 
00404         @code
00405         class MungingOutputFilter : FilterOutput
00406         {
00407                 int write (void[] src)
00408                 {
00409                         char[src.length] tmp;
00410 
00411                         // set everything to '*'
00412                         tmp = '*';
00413 
00414                         // write the munged output
00415                         return next.write (tmp);
00416                 }
00417         }
00418         @endcode
00419 
00420         Notice how the filter invokes the 'next' instance after 
00421         munging the content ... the far end of the chain is where
00422         the original IConduit writer is attached, so it will get
00423         invoked eventually assuming each filter invokes 'next'.
00424         If the next writer fails it will return IConduit.Eof, as
00425         should your filter (or throw an IOException). At the client 
00426         level, filters are attached like this:
00427 
00428         @code
00429         FileConduit fc = new FileConduit (...);
00430 
00431         fc.attach (new ZipOutputFilter);
00432         fc.attach (new MungingOutputFilter);
00433         @endcode
00434 
00435         Again, the last filter attached is the first one invoked 
00436         when a block of content is actually written. Each filter has
00437         two additional methods that it may use to control behavior:
00438 
00439         @code
00440         class FilterOutput : IFilterOutput
00441         {
00442                 protected IFilterOutput next;
00443 
00444                 void bind (IFilterOutput next)
00445                 {
00446                         this.next = next;
00447                 }
00448 
00449                 void unbind ()
00450                 {
00451                 }
00452         }
00453         @endcode
00454 
00455         The first method is invoked when the filter is attached to a 
00456         conduit, while the second is invoked just before the conduit 
00457         is closed. Both of these may be overridden by the filter for
00458         whatever purpose desired.
00459 
00460         Note that an output filter can choose to sidestep writing to 
00461         the conduit (per the usual case), and direct its output to 
00462         somewhere else entirely. This mechanism supports the notion
00463         of 'piping' between multiple conduits, or between a conduit 
00464         and something else entirely; as with the input-filter case,
00465         this is a bridging mechanism.
00466 
00467 *******************************************************************************/
00468 
00469 class ConduitSink : IConduitSink
00470 {
00471         protected IConduitSink next;
00472 
00473         /***********************************************************************
00474         
00475         ***********************************************************************/
00476 
00477         abstract int write (void[] src);
00478 
00479         /***********************************************************************
00480         
00481         ***********************************************************************/
00482 
00483         protected void bind (IConduitSink next)
00484         {
00485                 //printf ("bind output\n");
00486                 this.next = next;
00487         }
00488 
00489         /***********************************************************************
00490         
00491         ***********************************************************************/
00492 
00493         protected void unbind ()
00494         {
00495                 //printf ("unbind output\n");
00496                 next.unbind ();
00497         }
00498 }

Generated on Fri May 27 18:11:55 2005 for Mango by  doxygen 1.4.0