| /* |
| * Copyright 1999-2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cocoon.transformation; |
| |
| import java.io.IOException; |
| import java.util.Map; |
| |
| 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.avalon.framework.service.ServiceException; |
| import org.apache.avalon.framework.service.ServiceManager; |
| import org.apache.avalon.framework.service.ServiceSelector; |
| import org.apache.avalon.framework.service.Serviceable; |
| |
| import org.apache.avalon.excalibur.pool.Recyclable; |
| |
| import org.apache.cocoon.ProcessingException; |
| import org.apache.cocoon.components.modules.output.OutputModule; |
| import org.apache.cocoon.environment.SourceResolver; |
| import org.apache.cocoon.xml.dom.DocumentWrapper; |
| |
| import org.w3c.dom.Document; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * @cocoon.sitemap.component.documentation |
| * This transformer sieves an incoming stream of xml and extracts a |
| * document fragment from it depending on a given tag and stores the |
| * fragment using an OutputModule with a name based an attribute of |
| * another enclosing tag. Default configuration fires on |
| * <form-instance/> and uses @name of enclosing <form/> |
| * tag. Default OutputModule is request-attr. This is usefull in |
| * conjunction with the SimpleFormTransformer when setting the |
| * InputModule for it to a chain of request-param and request-attr so |
| * that the extracted form instance data is used only when no similar |
| * request parameter exists. |
| * |
| * @cocoon.sitemap.component.name simple-form-instance |
| * @cocoon.sitemap.component.logger sitemap.transformer.simple-form-instance |
| * |
| * @version $Id$ |
| */ |
| public class SimpleFormInstanceExtractionTransformer extends AbstractExtractionTransformer |
| implements Configurable, Serviceable, Recyclable { |
| |
| protected class ElementData { |
| public String uri = null; |
| public String loc = null; |
| public String raw = null; |
| |
| public ElementData() { |
| } |
| |
| public ElementData(String uri, String loc, String raw) { |
| this.uri = uri; |
| this.loc = loc; |
| this.raw =raw; |
| } |
| |
| public boolean equals(String uri, String loc, String raw) { |
| |
| if (!this.uri.equals(uri)) |
| return false; |
| if (!this.loc.equals(loc)) |
| return false; |
| if (!this.raw.equals(raw)) |
| return false; |
| return true; |
| } |
| |
| } |
| |
| protected final static String OUTPUT_MODULE_SELECTOR = OutputModule.ROLE+"Selector"; |
| |
| ElementData startElement = null; |
| ElementData nameElement = null; |
| String qname = "name"; |
| |
| String instanceName = null; |
| boolean nameAsRoot = true; |
| |
| String outputModuleName = "request-attr"; |
| Configuration outputConf = null; |
| |
| ServiceManager manager = null; |
| Map objectModel = null; |
| |
| public void configure(Configuration config) throws ConfigurationException { |
| this.startElement = new ElementData(); |
| this.startElement.uri = config.getChild("start").getAttribute("uri", ""); |
| this.startElement.loc = config.getChild("start").getAttribute("local-name", "form-instance"); |
| this.startElement.raw = config.getChild("start").getAttribute("raw-name", "form-instance"); |
| |
| this.nameElement = new ElementData(); |
| this.nameElement.uri = config.getChild("name").getAttribute("uri", ""); |
| this.nameElement.loc = config.getChild("name").getAttribute("local-name", "form"); |
| this.nameElement.raw = config.getChild("name").getAttribute("raw-name", "form"); |
| this.qname = config.getChild("name").getAttribute("name-attribute", "name"); |
| |
| this.nameAsRoot = config.getChild("name-as-root").getValueAsBoolean(this.nameAsRoot); |
| |
| this.outputConf = config.getChild("output"); |
| this.outputModuleName = this.outputConf.getAttribute("name",this.outputModuleName); |
| } |
| |
| public void service(ServiceManager manager) throws ServiceException { |
| this.manager = manager; |
| } |
| |
| /** Setup the transformer. */ |
| public void setup(SourceResolver resolver, Map objectModel, String src, Parameters parameters) |
| throws ProcessingException, SAXException, IOException { |
| super.setup(resolver, objectModel, src, parameters); |
| this.objectModel = objectModel; |
| } |
| |
| public void recycle() { |
| super.recycle(); |
| this.instanceName = null; |
| } |
| |
| /** |
| * 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. |
| * @return a <code>boolean</code> value to signal to start extracting |
| */ |
| public boolean startExtracting(String uri, String loc, String raw, Attributes a) { |
| if (this.nameElement.equals(uri,loc,raw)) { |
| this.instanceName = a.getValue(this.qname); |
| } |
| boolean res = this.startElement.equals(uri,loc,raw); |
| return res; |
| } |
| |
| /** |
| * 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 |
| * @return a <code>boolean</code> value to signal to stop extracting |
| */ |
| public boolean endExtracting(String uri, String loc, String raw) { |
| boolean res = this.startElement.equals(uri,loc,raw); |
| return res; |
| } |
| |
| |
| /** |
| * Start root element and replace it with the instance name. |
| * @see org.apache.cocoon.transformation.AbstractExtractionTransformer#startExtractingDocument(String, String, String, Attributes) |
| */ |
| public void startExtractingDocument(String uri, String loc, String raw, Attributes a) throws SAXException { |
| if (this.nameAsRoot) { |
| loc = this.instanceName; |
| if (uri != null && !uri.equals("")) { |
| int pos = raw.indexOf(':'); |
| raw = raw.substring(0, pos+1) + this.instanceName; |
| } else { |
| raw = loc; |
| } |
| } |
| this.currentBuilder.startElement(uri,loc,raw,a); |
| } |
| |
| /** |
| * End root element and replace it with the instance name. |
| * @see org.apache.cocoon.transformation.AbstractExtractionTransformer#endExtractingDocument(String, String, String) |
| */ |
| public void endExtractingDocument(String uri, String loc, String raw) throws SAXException{ |
| if(this.nameAsRoot){ |
| loc = this.instanceName; |
| if (uri != null && !uri.equals("")) { |
| int pos = raw.indexOf(':'); |
| raw = raw.substring(0, pos+1) + this.instanceName; |
| } else { |
| raw = loc; |
| } |
| } |
| this.currentBuilder.endElement(uri, loc, raw); |
| } |
| |
| |
| /** |
| * Receive notification of the end of the extracted Document. |
| * |
| * @param doc a <code>Document</code> value |
| */ |
| public void handleExtractedDocument(Document doc) { |
| |
| ServiceSelector outputSelector = null; |
| OutputModule output = null; |
| |
| try { |
| if (getLogger().isDebugEnabled()) |
| getLogger().debug("wrote ['"+this.instanceName+"'] to "+output+" using "+outputConf); |
| outputSelector = (ServiceSelector) this.manager.lookup(OUTPUT_MODULE_SELECTOR); |
| if (outputSelector.isSelectable(this.outputModuleName)) { |
| output = (OutputModule) outputSelector.select(this.outputModuleName); |
| } |
| output.setAttribute(outputConf, this.objectModel, this.instanceName, new DocumentWrapper(doc)); |
| output.commit(outputConf, this.objectModel); |
| if (getLogger().isDebugEnabled()) |
| getLogger().debug("wrote ['"+this.instanceName+"'] to "+output+" using "+outputConf); |
| |
| } catch (Exception e) { |
| if (getLogger().isWarnEnabled()) |
| getLogger().warn("Problem writing document data: "+e.getMessage()); |
| } finally { |
| if (outputSelector != null) { |
| if (output != null) { |
| outputSelector.release(output); |
| output = null; |
| } |
| this.manager.release(outputSelector); |
| } |
| } |
| this.instanceName = null; |
| } |
| |
| } |