001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.transformation;
018:
019: import java.io.IOException;
020: import java.util.Map;
021:
022: import org.apache.avalon.framework.configuration.Configurable;
023: import org.apache.avalon.framework.configuration.Configuration;
024: import org.apache.avalon.framework.configuration.ConfigurationException;
025: import org.apache.avalon.framework.parameters.Parameters;
026: import org.apache.avalon.framework.service.ServiceException;
027: import org.apache.avalon.framework.service.ServiceManager;
028: import org.apache.avalon.framework.service.ServiceSelector;
029: import org.apache.avalon.framework.service.Serviceable;
030:
031: import org.apache.cocoon.ProcessingException;
032: import org.apache.cocoon.components.modules.output.OutputModule;
033: import org.apache.cocoon.environment.SourceResolver;
034: import org.apache.cocoon.xml.dom.DocumentWrapper;
035:
036: import org.w3c.dom.Document;
037: import org.xml.sax.Attributes;
038: import org.xml.sax.SAXException;
039:
040: /**
041: * @cocoon.sitemap.component.documentation
042: * This transformer sieves an incoming stream of xml and extracts a
043: * document fragment from it depending on a given tag and stores the
044: * fragment using an OutputModule with a name based an attribute of
045: * another enclosing tag. Default configuration fires on
046: * <form-instance/> and uses @name of enclosing <form/>
047: * tag. Default OutputModule is request-attr. This is usefull in
048: * conjunction with the SimpleFormTransformer when setting the
049: * InputModule for it to a chain of request-param and request-attr so
050: * that the extracted form instance data is used only when no similar
051: * request parameter exists.
052: *
053: * @cocoon.sitemap.component.name simple-form-instance
054: * @cocoon.sitemap.component.logger sitemap.transformer.simple-form-instance
055: *
056: * @author <a href="mailto:haul@apache.org">Christian Haul</a>
057: * @version CVS $Id: SimpleFormInstanceExtractionTransformer.java 433543 2006-08-22 06:22:54Z crossley $
058: */
059: public class SimpleFormInstanceExtractionTransformer extends
060: AbstractExtractionTransformer implements Configurable,
061: Serviceable {
062:
063: protected static class ElementData {
064: public String uri = null;
065: public String loc = null;
066: public String raw = null;
067:
068: public ElementData() {
069: }
070:
071: public ElementData(String uri, String loc, String raw) {
072: this .uri = uri;
073: this .loc = loc;
074: this .raw = raw;
075: }
076:
077: public boolean equals(String uri, String loc, String raw) {
078:
079: if (!this .uri.equals(uri))
080: return false;
081: if (!this .loc.equals(loc))
082: return false;
083: if (!this .raw.equals(raw))
084: return false;
085: return true;
086: }
087:
088: }
089:
090: protected final static String OUTPUT_MODULE_SELECTOR = OutputModule.ROLE
091: + "Selector";
092:
093: ElementData startElement = null;
094: ElementData nameElement = null;
095: String qname = "name";
096:
097: String instanceName = null;
098: boolean nameAsRoot = true;
099:
100: String outputModuleName = "request-attr";
101: Configuration outputConf = null;
102:
103: ServiceManager manager = null;
104: Map objectModel = null;
105:
106: public void configure(Configuration config)
107: throws ConfigurationException {
108: this .startElement = new ElementData();
109: this .startElement.uri = config.getChild("start").getAttribute(
110: "uri", "");
111: this .startElement.loc = config.getChild("start").getAttribute(
112: "local-name", "form-instance");
113: this .startElement.raw = config.getChild("start").getAttribute(
114: "raw-name", "form-instance");
115:
116: this .nameElement = new ElementData();
117: this .nameElement.uri = config.getChild("name").getAttribute(
118: "uri", "");
119: this .nameElement.loc = config.getChild("name").getAttribute(
120: "local-name", "form");
121: this .nameElement.raw = config.getChild("name").getAttribute(
122: "raw-name", "form");
123: this .qname = config.getChild("name").getAttribute(
124: "name-attribute", "name");
125:
126: this .nameAsRoot = config.getChild("name-as-root")
127: .getValueAsBoolean(this .nameAsRoot);
128:
129: this .outputConf = config.getChild("output");
130: this .outputModuleName = this .outputConf.getAttribute("name",
131: this .outputModuleName);
132: }
133:
134: public void service(ServiceManager manager) throws ServiceException {
135: this .manager = manager;
136: }
137:
138: /** Setup the transformer. */
139: public void setup(SourceResolver resolver, Map objectModel,
140: String src, Parameters parameters)
141: throws ProcessingException, SAXException, IOException {
142: super .setup(resolver, objectModel, src, parameters);
143: this .objectModel = objectModel;
144: }
145:
146: public void recycle() {
147: super .recycle();
148: this .instanceName = null;
149: }
150:
151: /**
152: * Receive notification of the beginning of an element.
153: *
154: * @param uri The Namespace URI, or the empty string if the element has no
155: * Namespace URI or if Namespace
156: * processing is not being performed.
157: * @param loc The local name (without prefix), or the empty string if
158: * Namespace processing is not being performed.
159: * @param raw The raw XML 1.0 name (with prefix), or the empty string if
160: * raw names are not available.
161: * @param a The attributes attached to the element. If there are no
162: * attributes, it shall be an empty Attributes object.
163: * @return a <code>boolean</code> value to signal to start extracting
164: */
165: public boolean startExtracting(String uri, String loc, String raw,
166: Attributes a) {
167: if (this .nameElement.equals(uri, loc, raw)) {
168: this .instanceName = a.getValue(this .qname);
169: }
170: boolean res = this .startElement.equals(uri, loc, raw);
171: return res;
172: }
173:
174: /**
175: * Receive notification of the beginning of an element.
176: *
177: * @param uri The Namespace URI, or the empty string if the element has no
178: * Namespace URI or if Namespace
179: * processing is not being performed.
180: * @param loc The local name (without prefix), or the empty string if
181: * Namespace processing is not being performed.
182: * @param raw The raw XML 1.0 name (with prefix), or the empty string if
183: * @return a <code>boolean</code> value to signal to stop extracting
184: */
185: public boolean endExtracting(String uri, String loc, String raw) {
186: boolean res = this .startElement.equals(uri, loc, raw);
187: return res;
188: }
189:
190: /**
191: * Start root element and replace it with the instance name.
192: * @see org.apache.cocoon.transformation.AbstractExtractionTransformer#startExtractingDocument(String, String, String, Attributes)
193: */
194: public void startExtractingDocument(String uri, String loc,
195: String raw, Attributes a) throws SAXException {
196: if (this .nameAsRoot) {
197: loc = this .instanceName;
198: if (uri != null && !uri.equals("")) {
199: int pos = raw.indexOf(':');
200: raw = raw.substring(0, pos + 1) + this .instanceName;
201: } else {
202: raw = loc;
203: }
204: }
205: this .currentBuilder.startElement(uri, loc, raw, a);
206: }
207:
208: /**
209: * End root element and replace it with the instance name.
210: * @see org.apache.cocoon.transformation.AbstractExtractionTransformer#endExtractingDocument(String, String, String)
211: */
212: public void endExtractingDocument(String uri, String loc, String raw)
213: throws SAXException {
214: if (this .nameAsRoot) {
215: loc = this .instanceName;
216: if (uri != null && !uri.equals("")) {
217: int pos = raw.indexOf(':');
218: raw = raw.substring(0, pos + 1) + this .instanceName;
219: } else {
220: raw = loc;
221: }
222: }
223: this .currentBuilder.endElement(uri, loc, raw);
224: }
225:
226: /**
227: * Receive notification of the end of the extracted Document.
228: *
229: * @param doc a <code>Document</code> value
230: */
231: public void handleExtractedDocument(Document doc) {
232:
233: ServiceSelector outputSelector = null;
234: OutputModule output = null;
235:
236: try {
237: if (getLogger().isDebugEnabled())
238: getLogger().debug(
239: "wrote ['" + this .instanceName + "'] to "
240: + output + " using " + outputConf);
241: outputSelector = (ServiceSelector) this .manager
242: .lookup(OUTPUT_MODULE_SELECTOR);
243: if (outputSelector.isSelectable(this .outputModuleName)) {
244: output = (OutputModule) outputSelector
245: .select(this .outputModuleName);
246: }
247: output.setAttribute(outputConf, this .objectModel,
248: this .instanceName, new DocumentWrapper(doc));
249: output.commit(outputConf, this .objectModel);
250: if (getLogger().isDebugEnabled())
251: getLogger().debug(
252: "wrote ['" + this .instanceName + "'] to "
253: + output + " using " + outputConf);
254:
255: } catch (Exception e) {
256: if (getLogger().isWarnEnabled())
257: getLogger().warn(
258: "Problem writing document data: "
259: + e.getMessage());
260: } finally {
261: if (outputSelector != null) {
262: if (output != null) {
263: outputSelector.release(output);
264: output = null;
265: }
266: this.manager.release(outputSelector);
267: }
268: }
269: this.instanceName = null;
270: }
271:
272: }
|