You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by br...@apache.org on 2003/07/25 11:07:47 UTC
cvs commit: cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/transformation WidgetReplacingPipe.java WoodyTemplateTransformer.java
bruno 2003/07/25 02:07:47
Modified: src/blocks/woody/java/org/apache/cocoon/woody/transformation
WidgetReplacingPipe.java
WoodyTemplateTransformer.java
Log:
Applied bugzilla patch 21853 by Marc Portier + a few additions from myself
We now got a wt:form-template tag supporting JXPath expressions in the
action attribute and a location attribute for specifying where the form is (optional).
Revision Changes Path
1.4 +144 -13 cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/transformation/WidgetReplacingPipe.java
Index: WidgetReplacingPipe.java
===================================================================
RCS file: /home/cvs/cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/transformation/WidgetReplacingPipe.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- WidgetReplacingPipe.java 4 Jul 2003 17:51:53 -0000 1.3
+++ WidgetReplacingPipe.java 25 Jul 2003 09:07:46 -0000 1.4
@@ -50,17 +50,23 @@
*/
package org.apache.cocoon.woody.transformation;
-import org.apache.cocoon.xml.AbstractXMLPipe;
-import org.apache.cocoon.woody.formmodel.Widget;
-import org.apache.cocoon.woody.formmodel.Repeater;
-import org.apache.cocoon.woody.Constants;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Locale;
+
+import org.apache.avalon.excalibur.pool.Recyclable;
import org.apache.cocoon.components.sax.XMLByteStreamCompiler;
import org.apache.cocoon.components.sax.XMLByteStreamInterpreter;
-import org.apache.avalon.excalibur.pool.Recyclable;
-import org.xml.sax.SAXException;
+import org.apache.cocoon.woody.Constants;
+import org.apache.cocoon.woody.formmodel.Repeater;
+import org.apache.cocoon.woody.formmodel.Widget;
+import org.apache.cocoon.woody.formmodel.Form;
+import org.apache.cocoon.xml.AbstractXMLPipe;
+import org.apache.commons.jxpath.JXPathContext;
+import org.apache.commons.jxpath.JXPathException;
import org.xml.sax.Attributes;
-
-import java.util.Locale;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
/**
* The basic operation of this Pipe is that it replaces wi:widget tags (having an id attribute)
@@ -77,6 +83,11 @@
*
* <p>Additionally, this transformer supports the following tags:
* <ul>
+ * <li><strong>form-template</strong>: all other widget related tags should appear inside a form-template
+ * tag. The form-template tag should specify the location where the woody form can be retrieved in a "location"
+ * attribute, using a JXPath expression. If not specified, the default expression "/woody-form" is used.
+ * If the form-template tag has an action attribute, then all JXPath expressions in that attribute
+ * embedded inside #{...} will be evaluated.
* <li><strong>widget-label</strong>: used to insert the label of a widget. Requires an "id" attribute.
* <li><strong>repeater-widget</strong>: provides special treatement for repeater widgets. The content
* of the repeater-widget element will be used as a template to generate each of the rows of the repeater.
@@ -91,7 +102,12 @@
* <p>Woody ships with an XSL that can style all the widgets that are provided by the core Woody framework.
*/
public class WidgetReplacingPipe extends AbstractXMLPipe {
-
+
+ protected static final String FORM_TEMPLATE_EL = "form-template";
+ protected static final String STYLING_EL = "styling";
+ /** Default key under which the woody form is stored in the JXPath context. */
+ public static final String WOODY_FORM = "woody-form";
+
protected Widget contextWidget;
/** Indicates whether we're currently in a widget element. */
protected boolean inWidgetElement;
@@ -112,13 +128,13 @@
/** Boolean indicating wether the current widget requires special repeater-treatement. */
protected boolean repeaterWidget;
protected WoodyTemplateTransformer.InsertStylingContentHandler stylingHandler = new WoodyTemplateTransformer.InsertStylingContentHandler();
+ protected JXPathContext jxpathContext;
- protected static final String STYLING_EL = "styling";
-
- public void init(Widget contextWidget) {
+ public void init(Widget contextWidget, JXPathContext jxpathContext) {
this.contextWidget = contextWidget;
inWidgetElement = false;
elementNestingCounter = 0;
+ this.jxpathContext = jxpathContext;
}
public void startElement(String namespaceURI, String localName, String qName, Attributes attributes)
@@ -126,6 +142,7 @@
elementNestingCounter++;
if (!inWidgetElement && namespaceURI.equals(Constants.WT_NS)
&& (localName.equals("widget") || localName.equals("repeater-widget"))) {
+ checkContextWidgetAvailable(qName);
inWidgetElement = true;
widgetElementNesting = elementNestingCounter;
xmlCompiler.recycle();
@@ -139,9 +156,11 @@
xmlCompiler.startElement(namespaceURI, localName, qName, attributes);
} else if (namespaceURI.equals(Constants.WT_NS)) {
if (localName.equals("widget-label")) {
+ checkContextWidgetAvailable(qName);
Widget widget = getWidget(attributes);
widget.generateLabel(contentHandler);
} else if (localName.equals("repeater-widget-label")) {
+ checkContextWidgetAvailable(qName);
Widget widget = getWidget(attributes);
if (!(widget instanceof Repeater))
throw new SAXException("WoodyTemplateTransformer: the element \"repeater-widget-label\" can only be used for repeater widgets.");
@@ -150,12 +169,51 @@
throw new SAXException("WoodyTemplateTransformer: the element \"repeater-widget-label\" requires a \"widget-id\" attribute.");
((Repeater)widget).generateWidgetLabel(widgetId, contentHandler);
} else if (localName.equals("repeater-size")) {
+ checkContextWidgetAvailable(qName);
Widget widget = getWidget(attributes);
if (!(widget instanceof Repeater))
throw new SAXException("WoodyTemplateTransformer: the element \"repeater-size\" can only be used for repeater widgets.");
contentHandler.startPrefixMapping(Constants.WI_PREFIX, Constants.WI_NS);
((Repeater)widget).generateSize(contentHandler);
contentHandler.endPrefixMapping(Constants.WI_PREFIX);
+ } else if (localName.equals(FORM_TEMPLATE_EL)) {
+ if (contextWidget != null)
+ throw new SAXException("Detected nested wt:form-template elements, this is not allowed.");
+ contentHandler.startPrefixMapping(Constants.WI_PREFIX, Constants.WI_NS);
+
+ // Note: since the wt:form-template element is the top-level element in which
+ // all other widget elements must be nested, we can safely assume here that this
+ // instance of the WidgetReplacingPipe == WoodyTemplateTransformer
+ WoodyTemplateTransformer wtt = (WoodyTemplateTransformer)this;
+
+ // first look for the form using the location attribute, if any
+ String formJXPath = attributes.getValue("location");
+ if (formJXPath != null) {
+ Object form = jxpathContext.getValue(formJXPath);
+ if (form == null)
+ throw new SAXException("No form found at location \"" + formJXPath + "\".");
+ if (!(form instanceof Form))
+ throw new SAXException("Object returned by expression \"" + formJXPath + "\" is not a Woody Form.");
+ contextWidget = (Form)form;
+ } else if (wtt.attributeName != null) { // then see if an attribute-name was specified
+ contextWidget = (Form)wtt.request.getAttribute(wtt.attributeName);
+ if (contextWidget == null)
+ throw new SAXException("No form found in request attribute with name \"" + wtt.attributeName);
+ } else { // and then see if we got a form from the flow
+ formJXPath = "/" + WoodyTemplateTransformer.WOODY_FORM;
+ Object form = null;
+ try {
+ form = jxpathContext.getValue(formJXPath);
+ } catch (JXPathException e) {}
+ if (form != null)
+ contextWidget = (Form)form;
+ else
+ throw new SAXException("No Woody form found.");
+ }
+
+ String[] namesToTranslate = {"action"};
+ Attributes transAtts = translateAttributes(attributes, namesToTranslate);
+ contentHandler.startElement(Constants.WI_NS , FORM_TEMPLATE_EL, Constants.WI_PREFIX_COLON + FORM_TEMPLATE_EL, transAtts);
} else {
throw new SAXException("Unsupported WoodyTemplateTransformer element: " + localName);
}
@@ -164,6 +222,75 @@
}
}
+ private void checkContextWidgetAvailable(String widgetElementName) throws SAXException {
+ if (contextWidget == null)
+ throw new SAXException(widgetElementName + " cannot be used outside a wt:form-template element");
+ }
+
+ private Attributes translateAttributes(Attributes attributes, String[] names) {
+ AttributesImpl newAtts = new AttributesImpl(attributes);
+ if (names!= null) {
+ for (int i = 0; i < names.length; i++) {
+ String name = names[i];
+ int position = newAtts.getIndex(name);
+ String newValue = translateText(newAtts.getValue(position));
+ newAtts.setValue(position, newValue);
+ }
+ }
+ return newAtts;
+ }
+
+ /**
+ * Replaces JXPath expressions embedded inside #{ and } by their value.
+ */
+ private String translateText(String original) {
+ StringBuffer expression;
+ StringBuffer translated = new StringBuffer();
+ StringReader in = new StringReader(original);
+ int chr;
+ try {
+ while ((chr = in.read()) != -1) {
+ char c = (char) chr;
+ if (c == '#') {
+ chr = in.read();
+ if (chr != -1) {
+ c = (char) chr;
+ if (c == '{') {
+ expression = new StringBuffer();
+ boolean more = true;
+ while ( more ) {
+ more = false;
+ if ((chr = in.read()) != -1) {
+ c = (char)chr;
+ if (c != '}') {
+ expression.append(c);
+ more = true;
+ } else {
+ translated.append(evaluateExpression(expression.toString()));
+ }
+ } else {
+ translated.append('#').append('{').append(expression);
+ }
+ }
+ }
+ } else {
+ translated.append((char) chr);
+ }
+ } else {
+ translated.append(c);
+ }
+ }
+ } catch (IOException ignored) {
+ ignored.printStackTrace();
+ }
+
+ return translated.toString();
+ }
+
+ private String evaluateExpression(String expression) {
+ return jxpathContext.getValue(expression).toString();
+ }
+
protected Widget getWidget(Attributes attributes) throws SAXException {
String widgetId = attributes.getValue("id");
if (widgetId == null || widgetId.equals(""))
@@ -188,7 +315,7 @@
Object saxFragment = xmlCompiler.getSAXFragment();
for (int i = 0; i < rowCount; i++) {
Repeater.RepeaterRow row = repeater.getRow(i);
- rowPipe.init(row);
+ rowPipe.init(row, jxpathContext);
rowPipe.setContentHandler(contentHandler);
rowPipe.setLexicalHandler(lexicalHandler);
interpreter.setConsumer(rowPipe);
@@ -214,6 +341,10 @@
(localName.equals("widget-label") || localName.equals("repeater-widget-label")
|| localName.equals("repeater-size"))) {
// do nothing
+ } else if (namespaceURI.equals(Constants.WT_NS) && localName.equals(FORM_TEMPLATE_EL)) {
+ contextWidget = null;
+ contentHandler.endElement(Constants.WI_NS, FORM_TEMPLATE_EL, Constants.WI_PREFIX_COLON + FORM_TEMPLATE_EL);
+ contentHandler.endPrefixMapping(Constants.WI_PREFIX);
} else {
super.endElement(namespaceURI, localName, qName);
}
1.3 +30 -21 cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/transformation/WoodyTemplateTransformer.java
Index: WoodyTemplateTransformer.java
===================================================================
RCS file: /home/cvs/cocoon-2.1/src/blocks/woody/java/org/apache/cocoon/woody/transformation/WoodyTemplateTransformer.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- WoodyTemplateTransformer.java 4 Jul 2003 17:51:53 -0000 1.2
+++ WoodyTemplateTransformer.java 25 Jul 2003 09:07:46 -0000 1.3
@@ -53,38 +53,47 @@
import java.io.IOException;
import java.util.Map;
-import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.components.flow.FlowHelper;
+import org.apache.cocoon.components.flow.WebContinuation;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.transformation.Transformer;
-import org.apache.cocoon.woody.formmodel.Form;
+import org.apache.commons.jxpath.JXPathContext;
+import org.apache.commons.jxpath.Variables;
import org.xml.sax.SAXException;
/**
* See description of {@link WidgetReplacingPipe}.
*/
-public class WoodyTemplateTransformer
- extends WidgetReplacingPipe
- implements Transformer {
-
- public void setup(SourceResolver resolver, Map objectModel, String src, Parameters parameters) throws ProcessingException,
- SAXException, IOException {
-
- // get the form from a request attribute
- String formAttribute;
- try {
- formAttribute = parameters.getParameter("attribute-name");
- } catch (ParameterException e) {
- throw new ProcessingException("Missing 'attribute-name' parameter for WoodyTemplateTransformer.");
- }
+public class WoodyTemplateTransformer extends WidgetReplacingPipe implements Transformer {
+
+ /** Name of the request attribute under which the Woody form is stored (optional). */
+ protected String attributeName;
+ protected Request request;
+
+ public void setup(SourceResolver resolver, Map objectModel, String src, Parameters parameters)
+ throws ProcessingException, SAXException, IOException {
+
+ // create and set the jxpathContext...
+ Object flowContext = FlowHelper.getContextObject(objectModel);
+ WebContinuation wk = FlowHelper.getWebContinuation(objectModel);
+ JXPathContext jxpc = JXPathContext.newContext(flowContext);
+ Variables vars = jxpc.getVariables();
+ vars.declareVariable("continuation", wk);
Request request = ObjectModelHelper.getRequest(objectModel);
- Form form = (Form)request.getAttribute(formAttribute);
- if (form == null) {
- throw new ProcessingException("WoodyTemplateTransformer cannot find a form in the request attribute named " + formAttribute);
- }
- init(form);
+ vars.declareVariable("request", request);
+ Session session = request.getSession(false);
+ vars.declareVariable("session", session);
+ vars.declareVariable("parameters", parameters);
+
+ this.jxpathContext = jxpc;
+ this.attributeName = parameters.getParameter("attribute-name", null);
+ this.request = request;
+
+ init(null, jxpathContext);
}
}