You are viewing a plain text version of this content. The canonical link for it is here.
Posted to docs@cocoon.apache.org by do...@cocoon.apache.org on 2004/07/14 01:28:49 UTC

[Cocoon Wiki] New: XfolioOpenOfficeGeneration

   Date: 2004-07-13T16:28:48
   Editor: GlorieuxFrédéric <fr...@ajlsm.com>
   Wiki: Cocoon Wiki
   Page: XfolioOpenOfficeGeneration
   URL: http://wiki.apache.org/cocoon/XfolioOpenOfficeGeneration

   no comment

New Page:

= Abstract =

XfolioOpenOffice generation, one more time.
The issue is discussed in more than one place (sometimes by me)
this is my last cocoon solution to have a flat oo xml file,
with _caching_ ! 

= Status =

It works for me, in hope this helps others.
For Cocoon 2.1.5
Could be proposed as a commit in default cocoon ?

= Usage =

See [xfolio.xmap] 

{{{
  <map:match pattern="**.oo">
    <map:generate type="xsp" src="actions/oo.xsp">
      <map:parameter name="sxw" value="{context-attr:xfolio.efolder}{1}.sxw"/>
    </map:generate>
    <map:serialize type="xml"/>
  </map:match>
}}}

= How it works ? =

I need an OpenOffice generator, not only to provide an HTML view or some other transformation,
but also to extract metadata on vast amount of documents. I read all I can about OpenOffice generation and search for the best solution which should be
 * easy
 * fast
 * cacheable

  == Forget ==
 * default src="jar:myzip!myentry.xml" seems to load the file entry in memory,
but never remember the changes (isnt'it the goal to load a class from a jar one type ?)

  == Forrest ==

The best I found for now come from Forrest, using the new zip protocol from cocoon, able to resolve things like src="zip://content.xml@{folder}/test.sxw". This is a part of the trick. The problem of their solution is to use a cinclude transformer, which is not cacheable. I mean, you need to regenerate your aggregation each time it is requested. This is not a big problem in Forrest context (essentially generate a site), but on a real life server...

Their solution looks like that

{{{
<map:generate src="transform/cocoon/dummy.xml"/>
<map:transform src="transform/cocoon/sxw2oo.xsl">
  <map:parameter name="src" value="{context-attr:xfolio.efolder}{1}.sxw"/>
</map:transform>
<map:transform type="cinclude"/>
<map:serialize type="xml"/>
}}}

The dummy.xml is only there because you need something to begin with pure cocoon. 
The job is done by the XSL, to write something like that.
{{{
<office:document xmlns:**>
  <c:include select="/*/*">
    <xsl:attribute name="src">zip://meta.xml@<xsl:value-of select="$src"/></xsl:attribute>
  </c:include>
  <c:include select="/*/*">
    <xsl:attribute name="src">zip://content.xml@<xsl:value-of select="$src"/></xsl:attribute>
  </c:include>      
</office:document>
}}}

Problem are
 * an Xpath include is expensive (all document need to be loaded as DOM)
 * Cinclude (like Xinclude) haven't seem to be cacheable for me

You may say, try a {{<map:agreggate/>}}... I tried, and produce so much problems 
of validation that I stopped.

  == oo.xsp ==

The attached xsp do quite the same job as the excellent Forrest solution, 
with these differences
 * the generator is controlled and know the files on which check changes : 
the sxw, essentially (and also the xsp, for debug)


 * performances
    * direct pipe cost ~10 ms
    * xinclude cost ~160ms 
    * cinclude ~320ms
    * oo.xsp generator cost ~200ms on first call, but is _cached_ (~40 ms on second call)


  


= References =

  == useful ==

 * [http://cvs.apache.org/viewcvs.cgi/*checkout*/xml-forrest/src/core/context/forrest.xmap Forrest Open Office]
 * [http://wiki.apache.org/cocoon/XSPCachingWithCocoonHEAD XSPCaching]
 * [http://cvs.apache.org/viewcvs.cgi/*checkout*/cocoon-2.1/src/webapp/samples/xsp/xsp/Attic/cacheable.xsp]
 * [http://cvs.apache.org/viewcvs.cgi/*checkout*/cocoon-2.1/src/java/org/apache/cocoon/transformation/XIncludeTransformer.java XIncludeTransformer.java]
 * [http://cvs.apache.org/viewcvs.cgi/*checkout*/cocoon-2.1/src/java/org/apache/cocoon/components/source/impl/ZipSourceFactory.html  ZipSourceFactory.java]
 * [http://cvs.apache.org/viewcvs.cgi/*checkout*/cocoon-2.1/src/java/org/apache/cocoon/generation/FileGenerator.html  ZipSourceFactory.java]


  == bad examples ==

 * [http://wiki.apache.org/cocoon/JarProtocolExample  JarProtocolExample]
 * [http://wiki.apache.org/cocoon/OpenOfficeGeneration OpenOfficeGeneration]

= Rights =
  
(c) 2003, 2004 xfolio.org, ajlsm.com, strabon.org
Licence : GPL [http://www.gnu.org/copyleft/gpl.html]
 * created: 2003-07-10

'''FIXME: is it possible to update an attachement ?'''


= the code =

{{{
<xsp:page xmlns:xsp="http://apache.org/xsp">
  <xsp:structure>
    <xsp:include>org.apache.excalibur.source.Source</xsp:include>
    <xsp:include>org.apache.excalibur.source.SourceException</xsp:include>
    <xsp:include>org.apache.excalibur.source.SourceValidity</xsp:include>
    <xsp:include>org.apache.cocoon.components.source.SourceUtil</xsp:include>
    <xsp:include>org.apache.avalon.framework.parameters.ParameterException</xsp:include>
    <xsp:include>org.apache.excalibur.source.impl.validity.ExpiresValidity</xsp:include>
    <xsp:include>org.apache.excalibur.source.impl.validity.FileTimeStampValidity</xsp:include>
    <xsp:include>org.apache.excalibur.source.impl.validity.AggregatedValidity</xsp:include>
    <xsp:include>org.apache.cocoon.environment.SourceResolver</xsp:include>
    <xsp:include>java.io.Serializable</xsp:include>
    <xsp:include>java.util.Map</xsp:include>
    <xsp:include>org.apache.avalon.framework.parameters.Parameters</xsp:include>
    <xsp:include>org.apache.cocoon.xml.IncludeXMLConsumer</xsp:include>
  </xsp:structure>
  <xsp:logic>
    // artificial slowdown to make the effects of the cache visible
    final int DELAY_SECS = 2;


    /** The input source */
    protected Source sxwSource;
    protected Source xspSource;

    /**
     * From org.apache.cocoon.generation.FileGenerator
     *
     * Setup the file generator.
     * Try to get the last modification date of the source for caching.
     */

    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
        throws ProcessingException, SAXException, IOException {

        super.setup(resolver, objectModel, src, par);
        String sxw="";
        try {
          sxw = (String)parameters.getParameter("sxw");
          this.sxwSource = super.resolver.resolveURI(sxw);
        } catch (SourceException se) {
            throw SourceUtil.handle("oo.xsp, failed resolution sxw='" + sxw +"'.", se );
        } catch (ParameterException pe) {
           throw new ProcessingException ("oo.xsp, sxw param not found" , pe);
        }
        try {
            this.xspSource = super.resolver.resolveURI(src);
        } catch (SourceException se) {
            throw SourceUtil.handle("oo.xsp, failed resolution xsp='" + src + "'.", se);
        }

    }


    /**
     * Recycle this component.
     * All instance variables are set to <code>null</code>.
     */
    public void recycle() {
        if (null != this.sxwSource) {
            super.resolver.release(this.sxwSource);
            this.sxwSource = null;
        }
        if (this.xspSource != null) {
            super.resolver.release(this.xspSource);
            this.xspSource = null;
        }
        super.recycle();
    }
    
    /**
    * Generate the unique key for the cache.
    *
    * This key must be unique inside the space of this XSP page, it is used
    * to find the page contents in the cache (if getValidity says that the
    * contents are still valid).
    *
    * This method will be invoked before the getValidity() method.
    *
    * @return The generated key or null if the component
    *         is currently not cacheable.
    */
    
    public java.io.Serializable getKey() {
      
        String key=(this.sxwSource != null)?this.sxwSource.getURI():null;
        return key;
    }

    /**
    * Generate the validity object, tells the cache how long to
    * keep contents having this key around.
    *
    * Before this method can be invoked the getKey() method
    * will be invoked.
    *
    * In our case, validity combine the xsp file and the sxw file.
    *
    * @return The generated validity object or null if the
    *         component is currently not cacheable.
    */
    public SourceValidity getValidity() {
      AggregatedValidity out=new AggregatedValidity();
      if (this.sxwSource != null) out.add(this.sxwSource.getValidity());
      if (this.xspSource != null) out.add(this.xspSource.getValidity());
      return out;

    }



	</xsp:logic>
    <office:document xmlns:office="http://openoffice.org/2000/office" xmlns:style="http://openoffice.org/2000/style" xmlns:text="http://openoffice.org/2000/text" xmlns:table="http://openoffice.org/2000/table" xmlns:draw="http://openoffice.org/2000/drawing" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="http://openoffice.org/2000/meta" xmlns:number="http://openoffice.org/2000/datastyle" xmlns:svg="http://www.w3.org/2000/svg" xmlns:chart="http://openoffice.org/2000/chart" xmlns:dr3d="http://openoffice.org/2000/dr3d" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="http://openoffice.org/2000/form" xmlns:script="http://openoffice.org/2000/script" xmlns:config="http://openoffice.org/2001/config" office:class="text" office:version="1.0">
    <xsp:logic>
<![CDATA[

/*    
This debug commodity makes you sure that something is cached
(DELAY_SECS if create, less if cached)

          // slowdown page generation.
            try {
              Thread.sleep(DELAY_SECS * 1000L);
            } catch (InterruptedException ie) {
              // Not much that can be done...
            }

*/

// from org.apache.cocoon.transformation.XIncludeTransformer
SourceUtil.toSAX(super.resolver.resolveURI("zip://meta.xml@"+this.sxwSource.getURI()), new IncludeXMLConsumer(this.contentHandler));
SourceUtil.toSAX(super.resolver.resolveURI("zip://content.xml@"+this.sxwSource.getURI()), new IncludeXMLConsumer(this.contentHandler));

/*
an xpointer may be nicer (to conform to ooxmlflat), but much more
expensive, because it needs a complete DOM in memory
*/

]]>
    </xsp:logic>

    
    </office:document>
</xsp:page>

}}}