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.acting;
018:
019: import java.util.HashMap;
020: import java.util.Map;
021:
022: import org.apache.avalon.framework.activity.Disposable;
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.thread.ThreadSafe;
027:
028: import org.apache.avalon.excalibur.component.ComponentHandler;
029:
030: import org.apache.cocoon.components.sax.XMLByteStreamCompiler;
031: import org.apache.cocoon.components.sax.XMLByteStreamFragment;
032: import org.apache.cocoon.environment.ObjectModelHelper;
033: import org.apache.cocoon.environment.Redirector;
034: import org.apache.cocoon.environment.Request;
035: import org.apache.cocoon.environment.SourceResolver;
036: import org.apache.cocoon.generation.ServerPagesGenerator;
037: import org.apache.cocoon.xml.AbstractXMLConsumer;
038:
039: /**
040: * Allows actions to be written in XSP. This allows to use XSP to produce
041: * XML fragments that are later reused in generators.<br/>
042: *
043: * This action works in concert with the "action" logicheet, that offers
044: * actions-related services such as redirect or result map access, and the
045: * "capture" logicsheet that allows to capture parts of XSP-generated XML
046: * either as an <code>XMLizable</code> containing serialized SAX events,
047: * or as a DOM <code>Node</code>.<br/>
048: *
049: * As for generators, the XSP file name is set using the "src" attribute.<br/>
050: *
051: * This action accepts a single parameter, "output-attribute", which names
052: * the request attribute where the XSP-generated document will be stored
053: * (as an <code>XMLizable</code>). If this parameter is omitted, the
054: * XSP result is discarded (often the case when inner fragments are captured
055: * with the "capture" logicsheet").<br/>
056: *
057: * When "output-attribute" is set, the action status defaults to "success",
058: * meaning child sitemap statements are executed. This allows to use an
059: * existing XSP without modification with this action.<br/>
060: *
061: * When "output-attribute" isn't set, the action status defaults to "failure".
062: * The XSP must then use the "action" logicsheet to set its status.<br/>
063: *
064: * Example :
065: * <pre>
066: * <action type="serverpages" src="myAction.xsp">
067: * <map:param name="output-attribute" value="xsp-action-result"/>
068: * ...
069: * </action>
070: * </pre>
071: *
072: * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
073: * @version CVS $Id: ServerPagesAction.java 433543 2006-08-22 06:22:54Z crossley $
074: */
075: public class ServerPagesAction extends ConfigurableComposerAction
076: implements Disposable, ThreadSafe {
077:
078: public static final String REDIRECTOR_OBJECT = "xsp-action:redirector";
079: public static final String ACTION_RESULT_OBJECT = "xsp-action:result";
080: public static final String ACTION_SUCCESS_OBJECT = "xsp-action:success";
081:
082: ComponentHandler generatorHandler;
083:
084: public void configure(Configuration conf)
085: throws ConfigurationException {
086: try {
087: this .generatorHandler = ComponentHandler
088: .getComponentHandler(ServerPagesGenerator.class,
089: conf, this .manager, null, // Context
090: null, // RoleManager
091: null, // LogkitLoggerManager
092: null, // InstrumentManager
093: "N/A" // instrumentableName
094: );
095:
096: this .generatorHandler.enableLogging(getLogger());
097: this .generatorHandler.initialize();
098:
099: } catch (Exception e) {
100: throw new ConfigurationException(
101: "Cannot set up component handler", e);
102: }
103: }
104:
105: /* (non-Javadoc)
106: * @see org.apache.avalon.framework.activity.Disposable#dispose()
107: */
108: public void dispose() {
109: if (this .generatorHandler != null) {
110: this .generatorHandler.dispose();
111: this .generatorHandler = null;
112: }
113: }
114:
115: public Map act(Redirector redirector, SourceResolver resolver,
116: Map objectModel, String source, Parameters parameters)
117: throws Exception {
118:
119: if (this .getLogger().isDebugEnabled()) {
120: getLogger().debug("serverpage source: " + source);
121: }
122:
123: String outputKey = parameters.getParameter("output-attribute",
124: null);
125: Map resultMap = new HashMap();
126: Object success = null;
127:
128: // Get a ServerPagesGenerator
129: ServerPagesGenerator generator = (ServerPagesGenerator) this .generatorHandler
130: .get();
131:
132: // Generator output, if output-attribute was given
133: XMLByteStreamCompiler compiler = null;
134:
135: try {
136: generator.enableLogging(getLogger());
137: generator.compose(this .manager);
138: generator.setup(resolver, objectModel, source, parameters);
139:
140: // Setup generator output
141: if (outputKey == null) {
142: // discard output to a "black hole"
143: generator.setConsumer(new AbstractXMLConsumer() {
144: }); // Make the abstract class instanciable
145: } else {
146: // store output in a byte stream
147: compiler = new XMLByteStreamCompiler();
148: generator.setConsumer(compiler);
149: }
150:
151: // Augment the object model for the "action" logicsheet
152: objectModel.put(REDIRECTOR_OBJECT, redirector);
153: objectModel.put(ACTION_RESULT_OBJECT, resultMap);
154:
155: // Let the XSP do it's stuff
156: generator.generate();
157: success = objectModel.get(ACTION_SUCCESS_OBJECT);
158:
159: } finally {
160: // Release generator
161: generatorHandler.put(generator);
162:
163: // Clean up object model
164: objectModel.remove(REDIRECTOR_OBJECT);
165: objectModel.remove(ACTION_RESULT_OBJECT);
166: objectModel.remove(ACTION_SUCCESS_OBJECT);
167: }
168:
169: if (outputKey != null) {
170: // Success defaults to true when the whole output is captured
171: if (success == null) {
172: success = Boolean.TRUE;
173: }
174:
175: if (success == Boolean.TRUE) {
176: // Store the XSP output in the request
177: Request req = ObjectModelHelper.getRequest(objectModel);
178: req.setAttribute(outputKey, new XMLByteStreamFragment(
179: compiler.getSAXFragment()));
180: }
181: }
182:
183: return (success == Boolean.TRUE) ? resultMap : null;
184: }
185: }
|