Hi,
I try to redesign the fragmentextractor like the TODO list describes.
The problem, which I have, is that fragmentexractorgenerator doesn't find
the attributes in the session. The next problem is, that a "Out of time"
exception occures instead of a SAXException, if the generator doesn't find
the attribute.


<action context="code">
 Redesign FragmentExtractorGenerator/Transformer so that it works on a clustered
 server : store fragments in the session rather than in a local store. <br/>
 Additionnaly, store the fragments using the XMLCompiler instead of building a DOM.
</action>


Can anyone help me?
Thanx, Stephan Michels.
/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache Cocoon" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
package org.apache.cocoon.transformation;

import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.parameters.Parameters;

import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.caching.CacheValidity;
import org.apache.cocoon.caching.Cacheable;
import org.apache.cocoon.caching.NOPCacheValidity;
import org.apache.cocoon.components.sax.XMLSerializer;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.generation.FragmentExtractorGenerator2;

import org.w3c.dom.Document;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import java.io.IOException;
import java.rmi.server.UID;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


/**
 * The transformation half of the FragmentExtractor.
 * This transformer sieves an incoming stream of xml
 * and replaces fragments with an xlink locator pointing to the fragments.
 * <p>
 * The extracted fragments are idendified by their element name and namespace URI.
 * The default is to extract SVG images ("svg" elements in namespace
 * "http://www.w3.org/2000/svg";), but this can be overriden in the configuration:
 * <pre>
 *   &lt;extract-uri&gt;http://my/namespace/uri&lt;/extract-uri&gt;
 *   &lt;extract-element&gt;my-element&lt;/extract-element&gt;
 * </pre>
 * <p>
 * <b><em>Warning</em> : since fragments are stored locally in the class, this 
transformer
 * and the associated generator are very likely to fail on a clustered server.</b>
 *
 * @author <a href="mailto:[EMAIL PROTECTED]";>Paul Russell</a>
 * @version CVS $Id: FragmentExtractorTransformer.java,v 1.12 2002/02/14 08:52:45 
cziegeler Exp $
 */
public class FragmentExtractorTransformer extends AbstractTransformer
    implements Cacheable, Configurable, Composable, Disposable {

    private static final String EXTRACT_URI_NAME = "extract-uri";
    private static final String EXTRACT_ELEMENT_NAME = "extract-element";

    private static final String EXTRACT_URI = "http://www.w3.org/2000/svg";;
    private static final String EXTRACT_ELEMENT = "svg";

    private static final String FE_URI = 
"http://apache.org/cocoon/fragmentextractor/2.0";;
    private static final String XLINK_URI = "http://www.w3c.org/1999/xlink";;

    private String extractURI;
    private String extractElement;

    private static String generatorClass = 
"org.apache.cocoon.generation.FragmentExtractorGenerator";

    /** The component manager instance */
    protected ComponentManager manager = null;

    private XMLSerializer serializer;

    private Map prefixMap;

    private int extractLevel;

    //private int fragmentID;

    private Session session;
    private boolean sessionAvailable = false;

    /**
     * Configure this transformer.
     */
    public void configure(Configuration conf) throws ConfigurationException {
        if (conf != null) {
            this.extractURI = conf.getChild(EXTRACT_URI_NAME).getValue(EXTRACT_URI);
            this.extractElement = 
conf.getChild(EXTRACT_ELEMENT_NAME).getValue(EXTRACT_ELEMENT);
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("Extraction URI is " + this.extractURI);
                getLogger().debug("Extraction element is " + this.extractElement);
            }
        }
    }

    /** Setup the transformer. */
    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters 
parameters)
            throws ProcessingException, SAXException, IOException {
        extractLevel = 0;
        prefixMap = new HashMap();

        Request request = ObjectModelHelper.getRequest(objectModel);
        this.session = request.getSession(false);
        if (session == null) {
            sessionAvailable = false;
            getLogger().error("FragmentExtractorTransformer: no session object");
        }
        else
          sessionAvailable = true;
    }

    /**
     * Set the current <code>ComponentManager</code> instance used by this
     * <code>Composable</code>.
     */
    public void compose(ComponentManager manager) throws ComponentException {
        this.manager = manager;
    }

    /**
     * Release all resources.
     */
    public void dispose() {
        this.manager = null;
    }

    /**
     * Generate the unique key.
     * This key must be unique inside the space of this component.
     *
     * @return The generated key hashes the src
     */
    public long generateKey() {
        return 1;
    }

    /**
     * Generate the validity object.
     *
     * @return The generated validity object or <code>null</code> if the
     *         component is currently not cacheable.
     */
    public CacheValidity generateValidity() {
        return NOPCacheValidity.CACHE_VALIDITY;
    }

    /**
     * Receive notification of the beginning of a document.
     */
    public void startDocument() throws SAXException {
        super.startDocument();
    }

    /**
     * Receive notification of the end of a document.
     */
    public void endDocument() throws SAXException {
        super.endDocument();
    }

    /**
     * Begin the scope of a prefix-URI Namespace mapping.
     *
     * @param prefix The Namespace prefix being declared.
     * @param uri The Namespace URI the prefix is mapped to.
     */
    public void startPrefixMapping(String prefix, String uri)
    throws SAXException {
        if (extractLevel == 0) {
            super.startPrefixMapping(prefix,uri);
            prefixMap.put(prefix,uri);
        } else {
            //this.currentBuilder.startPrefixMapping(prefix,uri);
            this.serializer.startPrefixMapping(prefix,uri);
        }
    }

    /**
     * End the scope of a prefix-URI mapping.
     *
     * @param prefix The prefix that was being mapping.
     */
    public void endPrefixMapping(String prefix)
    throws SAXException {
        if (extractLevel == 0) {
            super.endPrefixMapping(prefix);
            prefixMap.remove(prefix);
        } else {
            //this.currentBuilder.endPrefixMapping(prefix);
            this.serializer.endPrefixMapping(prefix);
        }
    }

    /**
     * Receive notification of the beginning of an element.
     *
     * @param uri The Namespace URI, or the empty string if the element has no
     *            Namespace URI or if Namespace
     *            processing is not being performed.
     * @param loc The local name (without prefix), or the empty string if
     *            Namespace processing is not being performed.
     * @param raw The raw XML 1.0 name (with prefix), or the empty string if
     *            raw names are not available.
     * @param a The attributes attached to the element. If there are no
     *          attributes, it shall be an empty Attributes object.
     */
    public void startElement(String uri, String loc, String raw, Attributes a)
    throws SAXException {
        if (this.extractURI.equals(uri) && this.extractElement.equals(loc)) {
            extractLevel++;
            getLogger().debug("FragmentExtractorTransformer extractLevel now " + 
extractLevel + ".");

            // Start the document
            try {
              this.serializer = (XMLSerializer) 
this.manager.lookup(XMLSerializer.ROLE); 
            } catch (ComponentException ce) {
              throw new SAXException(
                "Could not lookup for XMLSerializer.", ce
              );
            }

            Iterator itt = prefixMap.entrySet().iterator();
            while (itt.hasNext()) {
                Map.Entry entry = (Map.Entry)itt.next();
                this.serializer.startPrefixMapping(
                    (String)entry.getKey(),
                    (String)entry.getValue()
                );
            }
        }

        if (extractLevel == 0) {
            super.startElement(uri,loc,raw,a);
        } else {
            this.serializer.startElement(uri,loc,raw,a);
        }
    }


    /**
     * Receive notification of the end of an element.
     *
     * @param uri The Namespace URI, or the empty string if the element has no
     *            Namespace URI or if Namespace
     *            processing is not being performed.
     * @param loc The local name (without prefix), or the empty string if
     *            Namespace processing is not being performed.
     * @param raw The raw XML 1.0 name (with prefix), or the empty string if
     *            raw names are not available.
     */
    public void endElement(String uri, String loc, String raw)
    throws SAXException {
        if (extractLevel == 0) {
            super.endElement(uri,loc,raw);
        } else {
            this.serializer.endElement(uri,loc,raw);
            if (this.extractURI.equals(uri) && this.extractElement.equals(loc)) {
                extractLevel--;
                getLogger().debug("FragmentExtractorTransformer extractLevel now " + 
extractLevel + ".");

                if (extractLevel == 0) {
                    // finish building the DOM. remove existing prefix mappings.
                    Iterator itt = prefixMap.entrySet().iterator();
                    while (itt.hasNext()) {
                        Map.Entry entry = (Map.Entry) itt.next();
                        this.serializer.endPrefixMapping(
                            (String)entry.getKey()
                        );
                    }
                    this.serializer.endDocument();

                    Object doc = this.serializer.getSAXFragment();

                    this.manager.release(this.serializer);

                    String id = (new UID()).toString();

                    // Cannot create File names with a ':' (in command-line 
generation)
                    // So replace ':' with '-'
                    id = id.replace(':','-');  

                    if (sessionAvailable)
                        session.setAttribute(id, doc);

                    getLogger().debug("FragmentExtractorTransformer stored document " 
+ id + ".");

                    // Insert ref.
                    super.startPrefixMapping("fe", FE_URI);
                    AttributesImpl atts = new AttributesImpl();
                    atts.addAttribute(null,"fragment-id","fragment-id","CDATA",id);
                    super.startElement(FE_URI,"fragment","fe:fragment",atts);
                    super.endElement(FE_URI,"fragment","fe:fragment");
                    super.endPrefixMapping("fe");
                }
            }
        }
    }

    /**
     * Receive notification of character data.
     *
     * @param c The characters from the XML document.
     * @param start The start position in the array.
     * @param len The number of characters to read from the array.
     */
    public void characters(char c[], int start, int len)
    throws SAXException {
        if (extractLevel == 0) {
            super.characters(c,start,len);
        } else {
            this.serializer.characters(c,start,len);
        }
    }

    /**
     * Receive notification of ignorable whitespace in element content.
     *
     * @param c The characters from the XML document.
     * @param start The start position in the array.
     * @param len The number of characters to read from the array.
     */
    public void ignorableWhitespace(char c[], int start, int len)
    throws SAXException {
        if (extractLevel == 0) {
            super.ignorableWhitespace(c,start,len);
        } else {
            this.serializer.ignorableWhitespace(c,start,len);
        }
    }

    /**
     * Receive notification of a processing instruction.
     *
     * @param target The processing instruction target.
     * @param data The processing instruction data, or null if none was
     *             supplied.
     */
    public void processingInstruction(String target, String data)
    throws SAXException {
        if (extractLevel == 0) {
            super.processingInstruction(target,data);
        } else {
            this.serializer.processingInstruction(target,data);
        }
    }

    /**
     * Receive notification of a skipped entity.
     *
     * @param name The name of the skipped entity.  If it is a  parameter
     *             entity, the name will begin with '%'.
     */
    public void skippedEntity(String name)
    throws SAXException {
        if (extractLevel == 0) {
            super.skippedEntity(name);
        } else {
            this.serializer.skippedEntity(name);
        }
    }

    /**
     * Report the start of DTD declarations, if any.
     *
     * @param name The document type name.
     * @param publicId The declared public identifier for the external DTD
     *                 subset, or null if none was declared.
     * @param systemId The declared system identifier for the external DTD
     *                 subset, or null if none was declared.
     */
    public void startDTD(String name, String publicId, String systemId)
    throws SAXException {
        if (extractLevel == 0) {
            super.startDTD(name,publicId,systemId);
        } else {
            throw new SAXException(
                "Recieved startDTD after beginning fragment extraction process."
            );
        }
    }

    /**
     * Report the end of DTD declarations.
     */
    public void endDTD()
    throws SAXException {
        if (extractLevel == 0) {
            super.endDTD();
        } else {
            throw new SAXException(
                "Recieved endDTD after beginning fragment extraction process."
            );
        }
    }

    /**
     * Report the beginning of an entity.
     *
     * @param name The name of the entity. If it is a parameter entity, the
     *             name will begin with '%'.
     */
    public void startEntity(String name)
    throws SAXException {
        if (extractLevel == 0) {
            super.startEntity(name);
        } else {
            this.serializer.startEntity(name);
        }
    }

    /**
     * Report the end of an entity.
     *
     * @param name The name of the entity that is ending.
     */
    public void endEntity(String name)
    throws SAXException {
        if (extractLevel == 0) {
            super.endEntity(name);
        } else {
            this.serializer.endEntity(name);
        }
    }

    /**
     * Report the start of a CDATA section.
     */
    public void startCDATA()
    throws SAXException {
        if (extractLevel == 0) {
            super.startCDATA();
        } else {
            this.serializer.startCDATA();
        }
    }

    /**
     * Report the end of a CDATA section.
     */
    public void endCDATA()
    throws SAXException {
        if (extractLevel == 0) {
            super.endCDATA();
        } else {
            this.serializer.endCDATA();
        }
    }

    /**
     * Report an XML comment anywhere in the document.
     *
     * @param ch An array holding the characters in the comment.
     * @param start The starting position in the array.
     * @param len The number of characters to use from the array.
     */
    public void comment(char ch[], int start, int len)
    throws SAXException {
        if (extractLevel == 0) {
            super.comment(ch,start,len);
        } else {
            this.serializer.comment(ch,start,len);
        }
    }

}
/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache Cocoon" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
package org.apache.cocoon.generation;

import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.parameters.Parameters;

import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.caching.CacheValidity;
import org.apache.cocoon.caching.Cacheable;
import org.apache.cocoon.caching.NOPCacheValidity;
import org.apache.cocoon.components.sax.XMLDeserializer;
import org.apache.cocoon.environment.AbstractEnvironment;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.util.HashUtil;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/** The generation half of FragmentExtractor.
 * FragmentExtractor is a transformer-generator pair which is designed to allow
 * sitemap managers to extract certain nodes from a SAX stream and move them
 * into a separate pipeline. The main use for this is to extract inline SVG
 * images and serve them up through a separate pipeline, usually serializing
 * them to PNG or JPEG format first.
 *
 * This is by no means complete yet, but it should prove useful, particularly
 * for offline generation.
 * <p>
 * <b><em>Warning</em> : since fragments are stored locally in the class, this 
generator
 * and the associated transformer are very likely to fail on a clustered server.</b>
 *
 * @author <a href="mailto:[EMAIL PROTECTED]";>Paul Russell</a>
 * @version CVS $Id: FragmentExtractorGenerator.java,v 1.6 2002/02/07 08:17:52 
cziegeler Exp $
 */
public class FragmentExtractorGenerator extends AbstractGenerator
        implements Composable, Cacheable {

    /** The component manager instance */
    protected ComponentManager manager = null;

    private Session session;

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

        Request request = ObjectModelHelper.getRequest(objectModel);
        this.session = request.getSession(false);
    }

    /**
     * Set the current <code>ComponentManager</code> instance used by this
     * <code>Composable</code>.
     */
    public void compose(ComponentManager manager) throws ComponentException {
        this.manager = manager;
    }

    /**
     * Generate the unique key.
     * This key must be unique inside the space of this component.
     *
     * @return The generated key hashes the src
     */
    public long generateKey() {
        return HashUtil.hash(source);
    }

    /**
     * Generate the validity object.
     *
     * @return The generated validity object or <code>null</code> if the
     *         component is currently not cacheable.
     */
    public CacheValidity generateValidity() {
        return NOPCacheValidity.CACHE_VALIDITY;
    }

    public void generate() throws SAXException {
        // Obtain the fragmentID  (which is simply the filename portion of the source)
        getLogger().debug("FragmentExtractorGenerator retrieving document " + source + 
".");

        Object doc = null;
        if (session==null)
            getLogger().error("FragmentExtractorGenerator: no session object");
        else 
            doc = session.getAttribute(source);

        if (doc == null)
            throw new SAXException("Could not find fragment " + source + ".");

        XMLDeserializer deserializer;
        try {
            deserializer = (XMLDeserializer) 
this.manager.lookup(XMLDeserializer.ROLE);
        } catch (ComponentException ce) {
            throw new SAXException(
                "Could not lookup for XMLDeserializer.", ce
            );
        }
  
        deserializer.setConsumer(this.xmlConsumer);
        deserializer.deserialize(doc);
    }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to