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.components.treeprocessor.sitemap;
018:
019: import java.util.ArrayList;
020: import java.util.Collections;
021: import java.util.List;
022: import java.util.Map;
023:
024: import org.apache.avalon.framework.component.ComponentManager;
025: import org.apache.avalon.framework.component.Composable;
026: import org.apache.avalon.framework.configuration.Configurable;
027: import org.apache.avalon.framework.configuration.Configuration;
028: import org.apache.avalon.framework.configuration.ConfigurationException;
029: import org.apache.cocoon.ProcessingException;
030: import org.apache.cocoon.components.flow.Interpreter;
031: import org.apache.cocoon.components.treeprocessor.AbstractProcessingNode;
032: import org.apache.cocoon.components.treeprocessor.InvokeContext;
033: import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
034: import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
035: import org.apache.cocoon.environment.Environment;
036: import org.apache.cocoon.environment.Redirector;
037: import org.apache.cocoon.sitemap.PatternException;
038:
039: /**
040: * Node handler for calling functions and resuming continuations in
041: * the control flow layer.
042: *
043: * @author <a href="mailto:ovidiu@apache.org">Ovidiu Predescu</a>
044: * @since March 13, 2002
045: * @version CVS $Id: CallFunctionNode.java 433543 2006-08-22 06:22:54Z crossley $
046: */
047: public class CallFunctionNode extends AbstractProcessingNode implements
048: Configurable, Composable {
049: protected List parameters;
050: protected VariableResolver functionName;
051: protected VariableResolver continuationId;
052: protected ComponentManager manager;
053: protected Interpreter interpreter;
054:
055: public static List resolveList(List expressions,
056: ComponentManager manager, InvokeContext context,
057: Map objectModel) throws PatternException {
058: int size;
059: if (expressions == null || (size = expressions.size()) == 0)
060: return Collections.EMPTY_LIST;
061:
062: List result = new ArrayList(size);
063:
064: for (int i = 0; i < size; i++) {
065: Interpreter.Argument arg = (Interpreter.Argument) expressions
066: .get(i);
067: String value = VariableResolverFactory.getResolver(
068: arg.value, manager).resolve(context, objectModel);
069: result.add(new Interpreter.Argument(arg.name, value));
070: }
071:
072: return result;
073: }
074:
075: public CallFunctionNode(VariableResolver functionName,
076: VariableResolver continuationId) {
077: this .functionName = functionName;
078: this .continuationId = continuationId;
079: }
080:
081: public void setInterpreter(Interpreter interp) throws Exception {
082: this .interpreter = interp;
083: }
084:
085: /**
086: * Obtain the configuration specific to this node type and update
087: * the internal state.
088: *
089: * @param config a <code>Configuration</code> value
090: * @exception ConfigurationException if an error occurs
091: */
092: public void configure(Configuration config)
093: throws ConfigurationException {
094: //TODO (SW): Deprecate this in the future.
095: // It has be found to be bad practice to pass sitemap parameters
096: // as function arguments, as these are name-value pairs in the sitemap
097: // and positional arguments in the flowscript. If the user doesn't respect
098: // the argument order, this leads to difficult to solve bugs.
099: parameters = new ArrayList();
100:
101: Configuration[] params = config.getChildren("parameter");
102: for (int i = 0; i < params.length; i++) {
103: Configuration param = params[i];
104: String name = param.getAttribute("name", null);
105: String value = param.getAttribute("value", null);
106: parameters.add(new Interpreter.Argument(name, value));
107: }
108: }
109:
110: public void compose(ComponentManager manager) {
111: this .manager = manager;
112: }
113:
114: public boolean invoke(Environment env, InvokeContext context)
115: throws Exception {
116: List params = null;
117:
118: // Resolve parameters
119: if (parameters != null) {
120: params = resolveList(parameters, manager, context, env
121: .getObjectModel());
122: }
123:
124: // Need redirector in any case
125: Redirector redirector = context.getRedirector();
126:
127: // If the continuation id is not null, it takes precedence over
128: // the function call, so we invoke it here.
129: String continuation = continuationId.resolve(context, env
130: .getObjectModel());
131: if (continuation != null && continuation.length() > 0) {
132: try {
133: interpreter.handleContinuation(continuation, params,
134: redirector);
135: } catch (Exception e) {
136: throw ProcessingException.throwLocated(
137: "Sitemap: error calling continuation", e,
138: getLocation());
139: }
140: if (!redirector.hasRedirected()) {
141: throw new ProcessingException(
142: "Sitemap: <map:call continuation> did not send a response",
143: getLocation());
144: }
145: return true;
146: }
147:
148: // We don't have a continuation id passed in <map:call>, so invoke
149: // the specified function
150: String name = functionName.resolve(context, env
151: .getObjectModel());
152: if (name != null && name.length() > 0) {
153: try {
154: interpreter.callFunction(name, params, redirector);
155: } catch (Exception e) {
156: throw ProcessingException.throwLocated(
157: "Sitemap: error calling function '" + name
158: + "'", e, getLocation());
159: }
160: if (!redirector.hasRedirected()) {
161: throw new ProcessingException(
162: "Sitemap: <map:call function> did not send a response",
163: getLocation());
164: }
165: return true;
166: }
167:
168: // Found neither continuation nor function to call
169: throw new ProcessingException(
170: "Sitemap: no function nor continuation given in <map:call function>",
171: getLocation());
172: }
173: }
|