1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
# $Id: Filter.pm,v 1.12 2002/01/10 20:39:44 rcaputo Exp $
package POE::Filter;
use strict;
use vars qw($VERSION);
$VERSION = (qw($Revision: 1.12 $ ))[1];
use Carp qw(croak);
#------------------------------------------------------------------------------
sub new {
my $type = shift;
croak "$type is not meant to be used directly";
}
#------------------------------------------------------------------------------
1;
__END__
=head1 NAME
POE::Filter - a protocol abstraction
=head1 SYNOPSIS
$filter = POE::Filter::Something->new();
$arrayref_of_logical_chunks =
$filter->get($arrayref_of_raw_chunks_from_driver);
$arrayref_of_streamable_chunks_for_driver =
$filter->put($arrayref_of_logical_chunks);
=head1 DESCRIPTION
Filters implement generic interfaces to low- and medium-level
protocols. Wheels use them to communicate in basic ways without
needing to know the details for doing so. For example, the Line
filter does everything needed to translate incoming streams into lines
and outgoing lines into streams. Sessions can get on with the
business of using lines.
=head1 PUBLIC FILTER METHODS
These methods are the generic Filter interface, and every filter must
implement them. Specific filters may have additional methods.
=over 2
=item new
new() creates and initializes a new filter. Specific filters may have
different constructor parameters.
=item get ARRAYREF
get() translates raw data into records. What sort of records is
defined by the specific filter. The method accepts a reference to an
array of raw data chunks, and it returns a reference to an array of
complete records. The returned ARRAYREF will be empty if there wasn't
enough information to create a complete record. Partial records may
be buffered until subsequent get() calls complete them.
my $records = $filter->get( $driver->get( $filehandle ) );
get() processes and returns as many records as possible. This is
faster than one record per call, but it introduces race conditions
when switching filters. If you design filters and intend them to be
switchable, please see get_one_start() and get_one().
=item get_one_start ARRAYREF
=item get_one
These methods are a second interface to a filter's input translation.
They split the usual get() into two stages.
get_one_start() accepts an array reference containing unprocessed
stream chunks. It adds them to the filter's internal buffer and does
nothing else.
get_one() takes no parameters and returns an ARRAYREF of zero or more
complete records from the filter's buffer. Unlike the plain get()
method, get_one() is not greedy. It returns as few records as
possible, preferrably just zero or one.
get_one_start() and get_one() reduce or eliminate race conditions when
switching filters in a wheel.
=item put ARRAYREF
put() serializes records into a form that may be written to a file or
sent across a socket. It accepts a reference to a list of records,
and it returns a reference to a list of stream chunks.
The list reference it returns may be passed directly to a driver.
$driver->put( $filter->put( \@records ) );
=item get_pending
get_pending() returns a filter's partial input buffer. Unlike
previous versions, the filter's input buffer is B<not> cleared. The
ReadWrite wheel uses this for hot-swapping filters; it gives partial
input buffers to the next filter.
get_pending() returns undef if nothing is pending. This is different
from get() and get_one().
Filters don't have output buffers. They accept complete records and
immediately pass the serialized information to a driver's queue.
It can be tricky keeping both ends of a socket synchronized during a
filter change. It's recommended that some sort of handshake protocol
be used to make sure both ends are using the same type of filter at
the same time.
TCP also tries to combine small packets for efficiency's sake. In a
streaming protocol, a filter change could be embedded between two data
chunks.
type-1 data
type-1 data
change to type-2 filter
type-2 data
type-2 data
A driver can easily read that as a single chunk. It will be passed to
a filter as a single chunk, and that filter (type-1 in the example)
will break the chunk into pieces. The type-2 data will be interpreted
as type-1 because the ReadWrite wheel hasn't had a chance to switch
filters yet.
Adding a handshake protocol means the sender will wait until a filter
change has been acknowledged before going ahead and sending data in
the new format.
=back
=head1 SEE ALSO
The SEE ALSO section in L<POE> contains a table of contents covering
the entire POE distribution.
=head1 BUGS
In theory, filters should be interchangeable. In practice, stream and
block protocols tend to be incompatible.
=head1 AUTHORS & COPYRIGHTS
Please see L<POE> for more information about authors and contributors.
=cut
|