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.woody.transformation;
018:
019: import java.io.IOException;
020: import java.io.StringReader;
021: import java.util.Locale;
022: import java.util.Map;
023:
024: import org.apache.avalon.framework.parameters.Parameters;
025: import org.apache.cocoon.components.flow.FlowHelper;
026: import org.apache.cocoon.components.flow.WebContinuation;
027: import org.apache.cocoon.environment.ObjectModelHelper;
028: import org.apache.cocoon.environment.Request;
029: import org.apache.cocoon.environment.Session;
030: import org.apache.cocoon.i18n.I18nUtils;
031: import org.apache.cocoon.woody.formmodel.Form;
032: import org.apache.cocoon.xml.AttributesImpl;
033: import org.apache.commons.jxpath.JXPathContext;
034: import org.apache.commons.jxpath.JXPathException;
035: import org.apache.commons.jxpath.Variables;
036: import org.xml.sax.Attributes;
037: import org.xml.sax.SAXException;
038:
039: /**
040: * WoodyPipeLineConfig
041: *
042: * @version CVS $Id: WoodyPipelineConfig.java 433543 2006-08-22 06:22:54Z crossley $
043: */
044: public class WoodyPipelineConfig {
045:
046: /**
047: * Default key under which the woody form is stored in the JXPath context.
048: */
049: public static final String WOODY_FORM = "woody-form";
050:
051: /**
052: * Name of the request attribute under which the Woody form is stored (optional). */
053: private final String attributeName;
054:
055: /**
056: * Pointer to the current request object. */
057: private final Request request;
058:
059: /**
060: * Initialized jxpathcontext to evaluate passed expressions with. */
061: private final JXPathContext jxpathContext;
062:
063: /**
064: * Containts locale specified as a parameter to the transformer, if any. */
065: private final Locale localeParameter;
066:
067: /**
068: * The locale currently used by the transformer. */
069: private Locale locale;
070:
071: /**
072: * Value for the action attribute of the form.
073: */
074: private String formAction;
075:
076: /**
077: * Value for the method attribute of the form.
078: */
079: private String formMethod;
080:
081: private WoodyPipelineConfig(JXPathContext jxpc, Request req,
082: Locale localeParam, String attName,
083: String actionExpression, String method) {
084: this .attributeName = attName;
085: this .request = req;
086: this .jxpathContext = jxpc;
087: this .localeParameter = localeParam;
088: this .formAction = translateText(actionExpression);
089: this .formMethod = method;
090: }
091:
092: /**
093: * Creates and initializes a WoodyPipelineConfig object based on the passed
094: * arguments of the setup() of the specific Pipeline-component.
095: *
096: * @param objectModel the objectmodel as passed in the setup()
097: * @param parameters the parameters as passed in the setup()
098: * @return an instance of WoodyPipelineConfig initialized according to the
099: * settings in the sitemap.
100: */
101: public static WoodyPipelineConfig createConfig(Map objectModel,
102: Parameters parameters) {
103: // create and set the jxpathContext...
104: Object flowContext = FlowHelper.getContextObject(objectModel);
105: WebContinuation wk = FlowHelper.getWebContinuation(objectModel);
106: JXPathContext jxpc = JXPathContext.newContext(flowContext);
107: Variables vars = jxpc.getVariables();
108: vars.declareVariable("continuation", wk);
109: Request request = ObjectModelHelper.getRequest(objectModel);
110: vars.declareVariable("request", request);
111: Session session = request.getSession(false);
112: vars.declareVariable("session", session);
113: vars.declareVariable("parameters", parameters);
114:
115: Locale localeParameter = null;
116: String localeStr = parameters.getParameter("locale", null);
117: if (localeStr != null) {
118: localeParameter = I18nUtils.parseLocale(localeStr);
119: }
120:
121: String attributeName = parameters.getParameter(
122: "attribute-name", null);
123: String actionExpression = parameters.getParameter(
124: "form-action", null);
125: String formMethod = parameters.getParameter("form-method",
126: "POST");
127: //TODO (20031223 mpo)think about adding form-encoding for the Generator.
128: // Note generator will also need some text to go on the submit-button?
129: // Alternative to adding more here is to apply xinclude ?
130:
131: return new WoodyPipelineConfig(jxpc, request, localeParameter,
132: attributeName, actionExpression, formMethod);
133: }
134:
135: /**
136: * Overloads {@link #findForm(String)} by setting the jxpath-expression to null
137: */
138: public Form findForm() throws SAXException {
139: return this .findForm(null);
140: }
141:
142: /**
143: * Finds the form from the current request-context based on the settings of
144: * this configuration object. The fall-back search-procedure is as follows:
145: * <ol><li>Use the provided jxpathExpression (if not null)</li>
146: * <li>Use the setting of the 'attribute-name' parameter on the request</li>
147: * <li>Obtain the form from it's default location in the flow context</li>
148: * </ol>
149: *
150: * @param jxpathExpression that should be pointing to the form
151: * @return the found form if found
152: * @throws SAXException in any of the following cases:
153: * <ul><li>The provided jxpathExpression (if not null) not point to a
154: * {@link Form} instance.</li>
155: * <li>The request is not holding a {@link Form} instance under the key
156: * specified by 'attribute-name' (if specified)</li>
157: * <li>Both jxpathExpression and 'attribute-name' were not specified AND
158: * also the default location was not holding a valid {@link Form} instance.</li>
159: * </ol>
160: */
161: public Form findForm(String jxpathExpression) throws SAXException {
162: Object form = null;
163: if (jxpathExpression != null) {
164: form = this .jxpathContext.getValue(jxpathExpression);
165: if (form == null) {
166: throw new SAXException("No form found at location \""
167: + jxpathExpression + "\".");
168: } else if (!(form instanceof Form)) {
169: throw new SAXException(
170: "Object returned by expression \""
171: + jxpathExpression
172: + "\" is not a Woody Form.");
173: }
174: } else if (this .attributeName != null) { // then see if an attribute-name was specified
175: form = this .request.getAttribute(this .attributeName);
176: if (form == null) {
177: throw new SAXException(
178: "No form found in request attribute with name \""
179: + this .attributeName + "\"");
180: } else if (!(form instanceof Form)) {
181: throw new SAXException(
182: "Object found in request (attribute = '"
183: + this .attributeName
184: + "') is not a Woody Form.");
185: }
186: } else { // and then see if we got a form from the flow
187: jxpathExpression = "/" + WoodyPipelineConfig.WOODY_FORM;
188: try {
189: form = this .jxpathContext.getValue(jxpathExpression);
190: } catch (JXPathException e) { /* do nothing */
191: }
192: if (form == null) {
193: throw new SAXException("No Woody form found.");
194: }
195: }
196: return (Form) form;
197: }
198:
199: /**
200: * Replaces JXPath expressions embedded inside #{ and } by their value.
201: * This will parse the passed String looking for #{} occurences and then
202: * uses the {@link #evaluateExpression(String)} to evaluate the found expression.
203: *
204: * @return the original String with it's #{}-parts replaced by the evaulated results.
205: */
206: public String translateText(String original) {
207: if (original == null) {
208: return null;
209: }
210:
211: StringBuffer expression;
212: StringBuffer translated = new StringBuffer();
213: StringReader in = new StringReader(original);
214: int chr;
215: try {
216: while ((chr = in.read()) != -1) {
217: char c = (char) chr;
218: if (c == '#') {
219: chr = in.read();
220: if (chr != -1) {
221: c = (char) chr;
222: if (c == '{') {
223: expression = new StringBuffer();
224: boolean more = true;
225: while (more) {
226: more = false;
227: if ((chr = in.read()) != -1) {
228: c = (char) chr;
229: if (c != '}') {
230: expression.append(c);
231: more = true;
232: } else {
233: translated
234: .append(evaluateExpression(
235: expression
236: .toString())
237: .toString());
238: }
239: } else {
240: translated.append('#').append('{')
241: .append(expression);
242: }
243: }
244: }
245: } else {
246: translated.append((char) chr);
247: }
248: } else {
249: translated.append(c);
250: }
251: }
252: } catch (IOException ignored) {
253: ignored.printStackTrace();
254: }
255: return translated.toString();
256: }
257:
258: /**
259: * Evaluates the passed xpath expression using the internal jxpath context
260: * holding the declared variables:
261: * <ol><li>continuation: as made available by flowscript</li>
262: * <li>request: as present in the cocoon processing environment</li>
263: * <li>session: as present in the cocoon processing environment</li>
264: * <li>parameters: as present in the cocoon sitemap node of the pipeline component</li></ol>
265: *
266: * @param expression
267: * @return the object-value resulting the expression evaluation.
268: */
269: public Object evaluateExpression(String expression) {
270: return this .jxpathContext.getValue(expression);
271: }
272:
273: public Locale getLocale() {
274: return locale;
275: }
276:
277: public void setLocale(Locale locale) {
278: this .locale = locale;
279: }
280:
281: public Locale getLocaleParameter() {
282: return localeParameter;
283: }
284:
285: /**
286: * The value for the wi:form-generated/@action.
287: * Note: wi:form-template copies this from its wt:form-template counterpart.
288: *
289: * @return the {@link #translateText(String)} result of the 'form-action' sitemap
290: * parameter to the pipeline component, or null if that parameter was not set.
291: */
292: public String getFormAction() {
293: return formAction;
294: }
295:
296: /**
297: * The value for the wi:form-generated/@method.
298: * Note: wi:form-template copies this from its wt:form-template counterpart.
299: *
300: * @return the value of the 'form-method' sitemap parameter to the pipeline
301: * component. Defaults to 'POST' if it was not set.
302: */
303: public String getFormMethod() {
304: return formMethod;
305: }
306:
307: /**
308: * The grouped attributes to set on the wi:form-generated element.
309: * Note: wi:form-template copies this from its wt:form-template counterpart.
310: *
311: * @see #getFormAction()
312: * @see #getFormMethod()
313: */
314: public Attributes getFormAttributes() {
315: AttributesImpl formAtts = new AttributesImpl();
316: if (getFormAction() != null) {
317: formAtts.addCDATAAttribute("action", getFormAction());
318: }
319: formAtts.addCDATAAttribute("method", getFormMethod());
320: return formAtts;
321: }
322: }
|