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> * <extract-uri>http://my/namespace/uri</extract-uri> * <extract-element>my-element</extract-element> * </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]