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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
/* -*- c++ -*- */
// $Id$
#include "ace/Message_Block.h"
#include "ace/Service_Object.h"
class JAWS_Protocol_Pipeline : public ACE_Service_Object
// = TITLE
// This is intended to be the base class of pipeline
// components.
//
{
public:
JAWS_Protocol_Pipeline (void);
JAWS_Protocol_Pipeline (JAWS_Protocol_Pipeline *pp);
virtual ~JAWS_Protocol_Pipeline (void);
int pull (ACE_Message_Block &mb);
// Method that initiates the work.
int push (ACE_Message_Block &mb);
// Method that notifies work is available.
virtual int pull_hook (ACE_Message_Block &mb) = 0;
// Required method that finishes the work.
virtual int push_hook (ACE_Message_Block &mb) = 0;
// Required method that accepts available work.
virtual int init (int, char *[]);
virtual int fini (void);
// Service Object initialization and finalization
protected:
void insert (JAWS_Protocol_Pipeline *pp);
void append (JAWS_Protocol_Pipeline *pp);
virtual JAWS_Protocol_Pipeline * prev_pipe (JAWS_Protocol_Pipeline *pp = 0);
// Virtual accessor to the preceding pipeline component
virtual JAWS_Protocol_Pipeline * next_pipe (JAWS_Protocol_Pipeline *pp = 0);
// Virtual accessor to the succeding pipeline component
};
class JAWS_Protocol_Filter : public JAWS_Protocol_Pipeline
// = TITLE
// This is intended to be the task skeleton of pipeline
// components.
//
{
public:
JAWS_Protocol_Filter (void);
JAWS_Protocol_Filter (JAWS_Protocol_Pipeline *pp);
// Constructors
virtual ~JAWS_Protocol_Filter (void);
// Destructor
void add (JAWS_Protocol_Pipeline *component);
// Insert a pipeline component into the pipeline chain
virtual int pull_hook (ACE_Message_Block &mb) = 0;
// Required method that finishes the work.
virtual int push_hook (ACE_Message_Block &mb) = 0;
// Required method that accepts available work.
private:
virtual JAWS_Protocol_Pipeline * prev_pipe (JAWS_Protocol_Pipeline *pp = 0);
// Virtual accessor to the preceding pipeline component
virtual JAWS_Protocol_Pipeline * next_pipe (JAWS_Protocol_Pipeline *pp = 0);
// Virtual accessor to the succeding pipeline component
protected:
JAWS_Protocol_Pipeline *prev_pipe_;
// The preceeding element in the pipeline chain.
JAWS_Protocol_Pipeline *next_pipe_;
// The succeeding element in the pipeline chain.
};
/*
This file describes the interfaces to the protocol pipeline
abstraction for JAWS. To understand how this is to work, let's
examine the processing path of a Web server.
CLIENT SERVER
+--------------.--------------+ +---------------.----------------+
|Issue Request |Display File | |Retrieve File |Receive Request |
+--------------^--------------+ +---------------^----------------+
11111111111111 66666666666666 333333333333333 2222222222222222
+--------------+ +---------------+
|Receive File | |Send File |
+--------------+ +---------------+
55555555555555 444444444444444
That is, a client issues a request. The server receives it, returns
content back to the client. The client then displays the content.
But, this ignores issues which surround processing of the content.
As a simple example, consider the case when the client has limited
screen real-estate and limited colors (as might be the case with
PDAs). Then, when the content involves an image, the processing
path involve the following additional stages:
CLIENT SERVER
+--------------.--------------+ +---------------.----------------+
|Issue Request |Display File | |Retreive File |Receive Request |
+--------------^--------------+ +---------------^----------------+
11111111111111 88888888888888 333333333333333 2222222222222222
+--------------+ +---------------+
|Dither Image | |Send File |
+--------------+ +---------------+
77777777777777 444444444444444
+--------------+
|Scale Image |
+--------------+
66666666666666
+--------------+
|Receive File |
+--------------+
55555555555555
After the server returns the content of the image to the client, the
client must scale the image to fit on its display device and then
dither the image to the number of colors which its display device
can support.
However, for a PDA with limited resources for battery life and
computation time, this may not be the optimal path for the file to
follow to achieve the best possible performance. For instance, due
to the bandwidth available to the PDA client, it may be better if
the server were to scale the image instead. In this case, the path
for the requested image would be viewed as the following:
CLIENT SERVER
+--------------.--------------+ +---------------.----------------+
|Issue Request |Display File | |Retreive File |Receive Request |
+--------------^--------------+ +---------------^----------------+
11111111111111 88888888888888 333333333333333 2222222222222222
+--------------+ +---------------+
|Dither Image | |Scale File |
+--------------+ +---------------+
77777777777777 444444444444444
+--------------+ +---------------+
|Receive File | |Send File |
+--------------+ +---------------+
66666666666666 555555555555555
The purpose of Pipeline is to provide a framework which allows for
this kind of negotiation to occur between a client and the server.
The protocol by which the client and server negotiate with each
other is left as an open issue. Solutions that can be used may
include use of special headers which identify which actions a client
would like the server to perform, or through PEP, the protocol
negotiation protocol.
*/
// Ok, let's figure out an interface that's going to work.
// These pipeline components should provide a method that allows me to
// chain a bunch of them together and then with a single method call,
// have data.
// The usual semantics of programatic pipelines like ours is that the
// first component makes a complete pass over the input before sending
// it to the next component. This seems like a reasonable semantic,
// but we can do some refinements.
// First, we do not want the hand-off of data to involve copying the
// data from the previous component to the next. This implies that
// between two consecutive components is a shared buffer. However, it
// is wasteful to have N+1 buffers for N pipeline components if the
// pipelines are going to be processing the input serially. This
// leads to the conclusion that only two buffers are necessary for the
// pipeline.
// Second, we need to decide how to specify the makeup or
// functionality of the protocol pipeline. In UNIX, this is done by
// the command line with "|" symbols between components. We too could
// use strings.
// Third, we need to decide how to build of these protocol pipelines.
// We may wish for static definitions to be constructed ala the
// Service Configurator. This implies that the Protocol Pipeline
// Factory is a Service Object, and it can accept a string which
// describes the components of the pipeline. Since we are using
// strings, it seems that each of the pipeline components themselves
// could also be considered Service Objects to be dynamically loaded.
// However, to maintain some notion of type safety, these pipeline
// components should probably have their own separate Configurator, so
// a Protocol Pipeline Configurator should be created.
|