I've had more time to look at James "pipeline" proposal.
Definitely looks reasonable.
However, I'd like to throw another idea. Probably worse,
but since this is a forum to experiment with new ideas,
here it is and let's see how it fares.
Thanks for commenting on it...
-- Pierre
What we're trying to achieve is to link tags that are producers of data
to tags that are consumers of that data, without the producer and
consumer having any knowledge of each other.
This collaboration between tags is already possible by simply having the
producer tag write to the 'previous out', which is then picked up by
the parent tag as its body content.
However, as James pointed out in his proposal, this is not the most
efficient way to do this in cases where double buffering occurs. This is why
James came up with the 'pipeline' proposal, which makes a lot of sense.
As I was trying to apply the 'pipeline' proposal to concrete cases,
I however had some concerns regarding its usage:
1. algorithm to link the producer to the consumer is 'tricky'
- Prior to producing its data, the producer tag must check with its
ancestors if one of them implements InputCapableTag or
OutputCapableTag. The exact algorithm used depends on
the 'type' of the producer's data.
- If this is an input stream
then
- Look for an InputCapableTag.
- If one is available
then
- call input() on it.
else
- Look for an OutputCapableTag.
- If one is available
then
- get the writer from the OutputCapableTag and copy
the input stream to it.
else
- copy the input stream to the previous out.
- else if this is an outputstream
then
- Look for an OutputCapableTag.
- If one is available
then
- get the writer from the OutputCapableTag and use it to
write the data. done.
else
- simply output to the 'previous out'
- else if this is another 'data type'
[similar to above, except that this data type must
be converted to the data types supported by the
InputCapableTag/OutputCapabletag interfaces.]
2. Requirement on the consumer tag to implement interface InputCapableTag or
OutputCapableTag.
Would be great if the producer data could be linked to
a consumer tag's attribute directly instead...
3. Restricted to a single 'pipeline' attribute
There are cases where I would like this "pipeline" concept
to apply to more than one attribute in the consumer tag.
For example, in the xsl taglib, there are two attributes that would
clearly benefit from this: xml (the XML data) and xsl (the XSL stylesheet).
It would be nice if the pipelining concept could be applied to both.
With the current proposal, this would only be doable for one of the two.
4. Tag attributes as tags
Finally, tag attributes whose value may be complex will usually
allow specifying that value in two different ways:
- as an attribute of the tag itself:
e.g. <scrape:page url="...">
- or as a tag itself:
<scrape:url>... producer tag...</scrape:url>
This appears to be just another case of wanting to direct the data
produced by a producer tag (or tag's body content) directly to
a specific attribute/property of the consumer's tag.
Would it be possible to avoid having to write these 'attribute tags'?
-----
So, given all of this, what if we had the following tag:
<tag:set property="propertyName">
that would be used to make this direct link between a producer
tag and a specific property/attribute of an ancestor consumer tag.
Reusing the spirit of James examples, we could have something that
would look as follows:
<xsl:apply>
<tag:set property="xsl">
<file:in path="/format_babelfish.xsl"/>
</tag:set>
<tag:set property="xml">
<http:soap
url="http://services.xmethods.net:80/perl/soaplite.cgi"
SOAPAction="urn:xmethodsBabelFish#BabelFish">
<tag:set property="body">
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:BabelFish xmlns:m="urn:xmethodsBabelFish">
<translationmode>en_fr</translationmode>
<sourcedata>SOAP is quite easy with JSP.</sourcedata>
</m:BabelFish>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</tag:set>
</http:soap>
</tag:set>
</xsl:apply>
In this example, xsl:apply is a consumer tag for two of its attributes:
xsl and xml. The data that feeds these attributes is provided via
the 'file' and 'http' producer tags. The http tag is also a consumer
tag for its 'body' attribute, whose data comes from the body content
of the <tag:set> that encloses it.
What's interesting with this approach is that the model for setting
the value of complex tag attributes comes much closer to the
"bean" model.
Advantages would be as follows:
- generic mechanism for efficiently setting 'complex' tag attributes
- no need to implement 'attribute' tags just to support complex
attribute values
- no need to implement interfaces InputCapableTag or OutputCapableTag
in a consumer tag
- data types supported by the consumer tag for this direct transfer
of data does not have to be restricted to just a few types, since
the <tagio:set> tag can handle all casting appropriately
- algorithm of the producer tag becomes very simple:
if parent tag is instanceof <tagio:set>
parent.setData(Object object)
else
simply write to the previous out
Disadvantages would be:
- need the extra <tagio:set> tag (which was not necessary in the
initial proposal)
- use of introspection (definitely has an impact on performance)
Clarification:
- If content of <tagio:set> is mixed (i.e. is anything other than a single
producer tag), then the <tag:set> body content is what is used as
the data.
Comments???