#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 1999-02-10 22:17 EST by <jcej@chiroptera.tragus.org>.
# Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/014'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#    414 -rw-r--r-- hdr
#     44 -rw-r--r-- bodies
#   2609 -rw-r--r-- page01.pre
#    231 -rw-r--r-- page02.pre
#    651 -rw-r--r-- page03.pre
#    439 -rw-r--r-- page04.pre
#   1079 -rw-r--r-- page05.pre
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if mkdir _sh28285; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= hdr ==============
if test -f 'hdr' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'hdr' '(file already exists)'
else
  $echo 'x -' extracting 'hdr' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'hdr' &&
<HTML>
<HEAD>
X   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
X   <META NAME="Author" CONTENT="Bob McWhirter">
X   <TITLE>ACE Tutorial 014</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
X
<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER>
X
<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER>
X
<P>
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 1012190598 'hdr' &&
  chmod 0644 'hdr' ||
  $echo 'restore of' 'hdr' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'hdr:' 'MD5 check failed'
25304aa689283dcbed9531b68e7ae2b9  hdr
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`"
    test 414 -eq "$shar_count" ||
    $echo 'hdr:' 'original size' '414,' 'current size' "$shar_count!"
  fi
fi
# ============= bodies ==============
if test -f 'bodies' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'bodies' '(file already exists)'
else
  $echo 'x -' extracting 'bodies' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'bodies' &&
PAGE=2
Task.h
Task.cpp
EndTask.h
stream.cpp
SHAR_EOF
  $shar_touch -am 1020193698 'bodies' &&
  chmod 0644 'bodies' ||
  $echo 'restore of' 'bodies' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'bodies:' 'MD5 check failed'
43305b4b15975a1e4cbd99b6d3592c12  bodies
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`"
    test 44 -eq "$shar_count" ||
    $echo 'bodies:' 'original size' '44,' 'current size' "$shar_count!"
  fi
fi
# ============= page01.pre ==============
if test -f 'page01.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page01.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page01.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page01.pre' &&
X
<p><b>ACE_Stream</b> is handy when you have several <b>ACE_Task</b> objects
that you would like to link together.
X
<p>An intermediate class you we will deal with is the <b>ACE_Module</b>.
X
<p>The basic plan is to wrap your <b>Task</b> into a <b>Module</b>, push 
the <b>Module</b> onto the <b>Stream</b>.  Do this for each <b>Task</b>,
X and then inject <b>Message_Block</b>s into the <b>Stream</b>.
X
<p>Each <b>Task</b> then processes the <b>Message_Block</b>, and forwards
it on to the next <b>Task</b> in the <b>Stream</b>.
X
<p>If you are not already familiar with <b>Message_Block</b>s and <b>Message_Queue</b>s,
I highly suggest that you check out <A HREF="../#MQ">Tutorials 10-13</A>.
X
<p>Streams can be used for both downstream and upstream movement of messages.  Used 
this way mirrors closely the way System V STREAMS work.  But you don't have to use them
bidirectionally.  In this tutorial, we only use one direction of the Stream.  Down.
X
<p>This tutorial is contributed by Bob McWhirter (bob@netwrench.com)
X
<P>
Kirthika's abstract:
<ul>
In this tutorial, an ACE_Stream has been implemented which has modules
flowing through it.(literally ;).
The chain of modules in the Stream include the Head and Tail Modules. A
Module is simply a reader-writer pair of ACE_Tasks with the writing side
acting as downstream and the reading side as upstream. Here we are only
concerned with going downstream so we install a Task into the write-side
of the module.
<P>
The task implementation makes use of flags to decide on whether to close
the main task or the service thread. The svc () method follows the
golden rule of copying message blocks before putting them on the queue
until it comes across a hang-up message. It then puts the message back
on the queue for its peers to obtain it and exits.
<P>
Any message put onto the Tail module is an error. So a customised
derivative of the Task class is created, which collects all the garbage
messages put onto the Tail. This End_Task is put into the Stream at the
start itself such that no modules whould ever follow it!
<P>
Then the other modules are pushed from the Tail-end into the Stream.
This is because we are interested in writing and not reading.
(Picture this to be a FIFO (queue) with head and tail nodes such
that the nodes are removed from the front and put into the queue from
the back) 
<P>
Each module then opens up the task which spawns threads and begins to
shove messgaes down the stream. Once we have got all the messages into
the stream, our job is completed and we shut down the Stream. 
<P>
A simple way to wade down the stream...;)
</ul>
SHAR_EOF
  $shar_touch -am 0210221599 'page01.pre' &&
  chmod 0644 'page01.pre' ||
  $echo 'restore of' 'page01.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page01.pre:' 'MD5 check failed'
23c8c084825939056b1c9226d4ab54c1  page01.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`"
    test 2609 -eq "$shar_count" ||
    $echo 'page01.pre:' 'original size' '2609,' 'current size' "$shar_count!"
  fi
fi
# ============= page02.pre ==============
if test -f 'page02.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page02.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page02.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page02.pre' &&
<P>
You find pretty soon that anytime you work with ACE_Task&lt;&gt; you
X	  have to create a derivative.  The Task.h header simply provides
X	  that derivative with the overrides we'll need in our application.
<P>
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 1012190598 'page02.pre' &&
  chmod 0644 'page02.pre' ||
  $echo 'restore of' 'page02.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page02.pre:' 'MD5 check failed'
4568ed757f3dbc1cebb7dc10d4768894  page02.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`"
    test 231 -eq "$shar_count" ||
    $echo 'page02.pre:' 'original size' '231,' 'current size' "$shar_count!"
  fi
fi
# ============= page03.pre ==============
if test -f 'page03.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page03.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page03.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page03.pre' &&
<P>
Before we get to main() let's take a look at the Task implementation.
X	  While we've overridden several methods, the real work is done in 
X	  the close() and svc() methods.
<P>
Notice how close() figures out if it is being called by the shutdown
X	  of the ACE_Stream or by the exit of svc().  The magic here is
X	  provided by the <i>flags</i> parameter.  By handling the stream
X	  shutdown in this way, we don't have to do anything strange in
X	  svc().  We also don't end up with extra hangup messages in the
X	  queue when the dust all settles down.
<P>
Like our other tutorials, svc() looks for a hangup and processes data.
<P>
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 1012190598 'page03.pre' &&
  chmod 0644 'page03.pre' ||
  $echo 'restore of' 'page03.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page03.pre:' 'MD5 check failed'
5c35812c1251ef1e8214fa9d9a18d496  page03.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`"
    test 651 -eq "$shar_count" ||
    $echo 'page03.pre:' 'original size' '651,' 'current size' "$shar_count!"
  fi
fi
# ============= page04.pre ==============
if test -f 'page04.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page04.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page04.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page04.pre' &&
<P>
As stated in the comments below, the default action of the task at the 
X	  stream tail is to treat any received data as an error.  In our
X	  implementation it will often happen that data gets through to
X	  the tail.  How, then, do we handle this without creating an
X	  error condition?  Simple:  Create a custom Task for use as the
X	  stream tail that doesn't consider it an error to receive data.
<P>
Read on...
<P>
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 1012190598 'page04.pre' &&
  chmod 0644 'page04.pre' ||
  $echo 'restore of' 'page04.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page04.pre:' 'MD5 check failed'
c6eaa0dbd1216734dcf83f5283d433f3  page04.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`"
    test 439 -eq "$shar_count" ||
    $echo 'page04.pre:' 'original size' '439,' 'current size' "$shar_count!"
  fi
fi
# ============= page05.pre ==============
if test -f 'page05.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page05.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page05.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page05.pre' &&
<P>
Now we come to main().  In the previous task-chain tutorial 
X	  every thread pool had to have the same number of threads.  This
X	  time around, we leverage the construction method of ACE_Stream
X	  and ACE_Module to customize the thread-pool size in each
X	  ACE_Task of the stream.
<P>
Remember EndTask from the previous page?  We create one here and push
X	  it into the stream to take care of cleaning up the messages.
X	  Technically, we could have replaced the default Tail task
X	  created by the ACE framework but it seems to make more sense to
X	  just push our "tail" onto the stream like the other tasks.  The
X	  caveat to this method is that you must be sure you don't push()
X	  any other Modules behind the EndTask!
<P>
Once the stream of modules containing tasks is all setup then we can
X	  put() some data into the stream for processing.  The clever use
X	  of Task::close() makes shutting downt the stream easier than
X	  ever.  No messing with hangup messages at the application level, 
X	  just close() when you're done!  What could be simpler?
<P>
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 1012190598 'page05.pre' &&
  chmod 0644 'page05.pre' ||
  $echo 'restore of' 'page05.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page05.pre:' 'MD5 check failed'
e1c3ef1d521db6daf9e432fb5582607d  page05.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`"
    test 1079 -eq "$shar_count" ||
    $echo 'page05.pre:' 'original size' '1079,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh28285
exit 0
