You are viewing a plain text version of this content. The canonical link for it is here.
Posted to taglibs-dev@jakarta.apache.org by James Strachan <ja...@metastuff.com> on 2001/02/23 12:26:28 UTC

PROPOSAL: tag pipelining

Tags can be nested with others, so that, for example, the result of a SOAP
request can be styled using the xsl tag library (which is kinda cool)...

<xsl:apply xsl="format_babelfish.xsl">
<http:soap
      url="http://services.xmethods.net:80/perl/soaplite.cgi"
      SOAPAction="urn:xmethodsBabelFish#BabelFish">
   <http: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>
   </http:body>
  </http:soap>
</xsl:apply>.

Though there is a small inefficency due to double buffering. The output of
the <http:soap> request is sent to the pageContext's JspWriter. The
<xsl:apply> creates its own BodyContent which gets filled by the output of
the <http:soap> request. It would be nice if we had some standard mechanism
for us to avoid the unnecessary buffer and "pipe" the input and output tags
together.

This is a similar idea to Pierre's iotransformer tag library though its done
at the inter-tag level rather than via a new tag and an explicit transformer
bean. For example if we had a standard interface...

public interface InputCapableTag {
    public void input( Reader reader );
    public void input( InputStream in );
}

Then the <http:soap> tag could look up the tag hierarchy for a tag which
implements InputCapableTag. Then if the <xsl:apply> tag implemented
InputCapableTag, the <http:soap> tag could pass the InputStream or Reader of
the result of the soap request directly to the <xsl:apply> tag without the
need for the output to be written to the BodyContent first.

A similar pattern in reverse could be done to supply the body of a
<http:request action="POST">. For example...

<http:soap
      url="http://services.xmethods.net:80/perl/soaplite.cgi"
      SOAPAction="urn:xmethodsBabelFish#BabelFish">
   <http:body>
     <xsl:apply xsl="make_soap_request.xsl">
          <m:BabelFish xmlns:m="urn:xmethodsBabelFish">
             <translationmode>en_fr</translationmode>
             <sourcedata>SOAP is quite easy with JSP.</sourcedata>
          </m:BabelFish>
      </xsl:apply>
    </http:body>
  </http:soap>

In the above example, we're using the <xsl:apply> tag to create the body of
the SOAP request. So here the <xsl:apply> tag creates the input and the
<http:soap> uses it for the body fo the HTTP POST. Again double buffering is
done - the output of the <xsl:apply> tag is written to the BodyContent of
the <http:body> tag first before being read and output to the
HttpURLConnection inside the <http:soap> tag.

It would be nice if we could avoid using the <http:body> tag completely and
instead use inter-tag communication (or "tag pipelining") as follows:-

<http:soap
      url="http://services.xmethods.net:80/perl/soaplite.cgi"
      SOAPAction="urn:xmethodsBabelFish#BabelFish">
   <xsl:apply xsl="make_soap_request.xsl">
        <m:BabelFish xmlns:m="urn:xmethodsBabelFish">
          <translationmode>en_fr</translationmode>
          <sourcedata>SOAP is quite easy with JSP.</sourcedata>
        </m:BabelFish>
   </xsl:apply>
  </http:soap>

In this case the <xsl:apply> tag searches the tag hierarchy for an instance
of OutputCapableTag

public interface OutputCapableTag {
    public void output( Writer writer );
    public void output( OutputStream out );
}

and so rather than the <xsl:apply> tag outputting its results directly to
the BodyContent it pipelines it straight into the <http:soap> tag which
results in the output being written straight through to the
HttpURLConnection.

It would be nice of some mechanism like the above could be adopted
throughout the jakarta-taglibs project as a standard way of pipelining tags
using nesting. So multiple 'pipelines' can be achieved as follows...

<file:write file="foo.txt">
    <regexp:subsitiute from="foo" to="bar">
    <xsl:apply xsl="something.xsl">
        <http:request url="foo" action="POST">
            <xsl:apply xsl="a.xsl" xml="bar.xml"/>
        </http:request>
    <xsl:apply>
</file:write>

This turns out to be quite similar to Pierre's proposal but done implicitly,
where each JSP custom tag becomes a a kind of  'transformer bean' and they
can connect their input/output together via tag interfaces (InputCapableTag
and OutputCapableTag).

If something like this gets accepted then it would be nice to have some
small core library "jakarta-core.jar" that contained the above interfaces
(and maybe some other helper / utility classes) that could be shared across
all of the tag libraries so that all jakarta-taglibs could efficiently
pipeline together.

Does this seem a reasonable idea?

<James/>


James Strachan
=============
email: james@metastuff.com
web: http://www.metastuff.com

__________________________________________________________________

If you are not the addressee of this confidential e-mail and any 
attachments, please delete it and inform the sender; unauthorised 
redistribution or publication is prohibited. 
Views expressed are those of the author and do not necessarily 
represent those of Citria Limited.
__________________________________________________________________

Re: PROPOSAL: tag pipelining

Posted by Pierre Delisle <pi...@sun.com>.
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???

Re: PROPOSAL: tag pipelining

Posted by Pierre Delisle <pi...@sun.com>.
James,

Your proposal makes a lot of sense. In iotransformer, I had toyed with the
idea of adding the parent tag as one additional type of 'source/sink',
but had left it aside for the time being.

I'm just back from a vacation. I'll get back shortly with more comments.

    -- Pierre

Re: PROPOSAL: tag pipelining

Posted by Eduardo Pelegri-Llopart <Ed...@eng.sun.com>.
I think it would be great to explore this space.  It has been in my todo
list for a while.  A variation is to explore SAX-aware or perhaps
JDOM-aware tags in a similar manner.

If enough consensus were reached, the tag interfaces could migrate into
an official standard.  The SAX/JDOM type of tags could even interact
automatically with JSP in XML syntax so XML elements are passed as
events.

	- eduard/o


James Strachan wrote:
> 
> Tags can be nested with others, so that, for example, the result of a SOAP
> request can be styled using the xsl tag library (which is kinda cool)...
> 
> <xsl:apply xsl="format_babelfish.xsl">
> <http:soap
>       url="http://services.xmethods.net:80/perl/soaplite.cgi"
>       SOAPAction="urn:xmethodsBabelFish#BabelFish">
>    <http: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>
>    </http:body>
>   </http:soap>
> </xsl:apply>.
> 
> Though there is a small inefficency due to double buffering. The output of
> the <http:soap> request is sent to the pageContext's JspWriter. The
> <xsl:apply> creates its own BodyContent which gets filled by the output of
> the <http:soap> request. It would be nice if we had some standard mechanism
> for us to avoid the unnecessary buffer and "pipe" the input and output tags
> together.
> 
> This is a similar idea to Pierre's iotransformer tag library though its done
> at the inter-tag level rather than via a new tag and an explicit transformer
> bean. For example if we had a standard interface...
> 
> public interface InputCapableTag {
>     public void input( Reader reader );
>     public void input( InputStream in );
> }
> 
> Then the <http:soap> tag could look up the tag hierarchy for a tag which
> implements InputCapableTag. Then if the <xsl:apply> tag implemented
> InputCapableTag, the <http:soap> tag could pass the InputStream or Reader of
> the result of the soap request directly to the <xsl:apply> tag without the
> need for the output to be written to the BodyContent first.
> 
> A similar pattern in reverse could be done to supply the body of a
> <http:request action="POST">. For example...
> 
> <http:soap
>       url="http://services.xmethods.net:80/perl/soaplite.cgi"
>       SOAPAction="urn:xmethodsBabelFish#BabelFish">
>    <http:body>
>      <xsl:apply xsl="make_soap_request.xsl">
>           <m:BabelFish xmlns:m="urn:xmethodsBabelFish">
>              <translationmode>en_fr</translationmode>
>              <sourcedata>SOAP is quite easy with JSP.</sourcedata>
>           </m:BabelFish>
>       </xsl:apply>
>     </http:body>
>   </http:soap>
> 
> In the above example, we're using the <xsl:apply> tag to create the body of
> the SOAP request. So here the <xsl:apply> tag creates the input and the
> <http:soap> uses it for the body fo the HTTP POST. Again double buffering is
> done - the output of the <xsl:apply> tag is written to the BodyContent of
> the <http:body> tag first before being read and output to the
> HttpURLConnection inside the <http:soap> tag.
> 
> It would be nice if we could avoid using the <http:body> tag completely and
> instead use inter-tag communication (or "tag pipelining") as follows:-
> 
> <http:soap
>       url="http://services.xmethods.net:80/perl/soaplite.cgi"
>       SOAPAction="urn:xmethodsBabelFish#BabelFish">
>    <xsl:apply xsl="make_soap_request.xsl">
>         <m:BabelFish xmlns:m="urn:xmethodsBabelFish">
>           <translationmode>en_fr</translationmode>
>           <sourcedata>SOAP is quite easy with JSP.</sourcedata>
>         </m:BabelFish>
>    </xsl:apply>
>   </http:soap>
> 
> In this case the <xsl:apply> tag searches the tag hierarchy for an instance
> of OutputCapableTag
> 
> public interface OutputCapableTag {
>     public void output( Writer writer );
>     public void output( OutputStream out );
> }
> 
> and so rather than the <xsl:apply> tag outputting its results directly to
> the BodyContent it pipelines it straight into the <http:soap> tag which
> results in the output being written straight through to the
> HttpURLConnection.
> 
> It would be nice of some mechanism like the above could be adopted
> throughout the jakarta-taglibs project as a standard way of pipelining tags
> using nesting. So multiple 'pipelines' can be achieved as follows...
> 
> <file:write file="foo.txt">
>     <regexp:subsitiute from="foo" to="bar">
>     <xsl:apply xsl="something.xsl">
>         <http:request url="foo" action="POST">
>             <xsl:apply xsl="a.xsl" xml="bar.xml"/>
>         </http:request>
>     <xsl:apply>
> </file:write>
> 
> This turns out to be quite similar to Pierre's proposal but done implicitly,
> where each JSP custom tag becomes a a kind of  'transformer bean' and they
> can connect their input/output together via tag interfaces (InputCapableTag
> and OutputCapableTag).
> 
> If something like this gets accepted then it would be nice to have some
> small core library "jakarta-core.jar" that contained the above interfaces
> (and maybe some other helper / utility classes) that could be shared across
> all of the tag libraries so that all jakarta-taglibs could efficiently
> pipeline together.
> 
> Does this seem a reasonable idea?
> 
> <James/>
> 
> James Strachan
> =============
> email: james@metastuff.com
> web: http://www.metastuff.com
> 
> __________________________________________________________________
> 
> If you are not the addressee of this confidential e-mail and any
> attachments, please delete it and inform the sender; unauthorised
> redistribution or publication is prohibited.
> Views expressed are those of the author and do not necessarily
> represent those of Citria Limited.
> __________________________________________________________________