KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > transformation > JPathTransformer


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.transformation;
17
18 import java.io.IOException JavaDoc;
19 import java.util.HashMap JavaDoc;
20 import java.util.Map JavaDoc;
21
22 import org.apache.avalon.framework.activity.Initializable;
23 import org.apache.avalon.framework.parameters.Parameters;
24 import org.apache.cocoon.ProcessingException;
25 import org.apache.cocoon.components.flow.FlowHelper;
26 import org.apache.cocoon.components.flow.WebContinuation;
27 import org.apache.cocoon.environment.SourceResolver;
28 import org.apache.commons.jxpath.JXPathContext;
29 import org.apache.regexp.RE;
30 import org.xml.sax.Attributes JavaDoc;
31 import org.xml.sax.SAXException JavaDoc;
32 import org.xml.sax.helpers.AttributesImpl JavaDoc;
33
34 /**
35  * @cocoon.sitemap.component.documentation
36  * Transformer implementation of the JPath XSP tag library.
37  *
38  * @cocoon.sitemap.component.name jpath
39  * @cocoon.sitemap.component.logger sitemap.transformer.jpath
40  *
41  *
42  * <p>
43  * This transformer (so far) supports the following jpath elements:
44  *
45  * <ul>
46  * <li>&lt;jpath:value-of select=".."/&gt; element.
47  * <li>&lt;jpath:continuation/&gt; element.
48  * <li>&lt;jpath:if test=".."&gt;..&lt;/jpath:if&gt; element.
49  * <li>jpath:action attribute on all elements that implicitly replaces any
50  * occurance of the string 'id' with the continuation id (useful when
51  * writing form action attributes). eg:
52  * <pre>&lt;form name="myform" jpath:action="../cont/id"&gt;..&lt;/form&gt;</pre>
53  * </ul>
54  * </p>
55  *
56  * @author <a HREF="mailto:crafterm@apache.org">Marcus Crafter</a>
57  * @version $Id: JPathTransformer.java 168366 2005-05-05 18:23:18Z vgritsenko $
58  */

59 public class JPathTransformer extends AbstractSAXTransformer
60                               implements Initializable {
61
62     /** namespace constant */
63     public static final String JavaDoc JPATH_NAMESPACE_URI = "http://apache.org/xsp/jpath/1.0";
64
65     /** jpath:action attribute constant */
66     public static final String JavaDoc JPATH_ACTION = "jpath:action";
67
68     /** jpath:value-of element constant */
69     public static final String JavaDoc JPATH_VALUEOF = "value-of";
70
71     /** jpath:value-of select attribute constant */
72     public static final String JavaDoc JPATH_VALUEOF_SELECT = "select";
73
74     /** jpath:continuation element constant */
75     public static final String JavaDoc JPATH_CONTINUATION = "continuation";
76
77     /** jpath:continuation select attribute constant */
78     public static final String JavaDoc JPATH_CONTINUATION_SELECT = "select";
79
80     /** jpath:if element constant */
81     public static final String JavaDoc JPATH_IF = "if";
82
83     /** jpath generic test attribute */
84     public static final String JavaDoc JPATH_TEST = "test";
85
86     // web contination
87
private WebContinuation m_kont;
88
89     // regular expression for matching 'id' strings with jpath:action
90
private RE m_re;
91
92     // jxpath context
93
private JXPathContext m_jxpathContext;
94
95     // jpath:value-of variable cache
96
private Map JavaDoc m_cache;
97
98     /**
99      * Initialize this transformer.
100      *
101      * @exception Exception if an error occurs
102      */

103     public void initialize() throws Exception JavaDoc {
104         this.defaultNamespaceURI = JPATH_NAMESPACE_URI;
105         m_re = new RE("id");
106         m_cache = new HashMap JavaDoc();
107     }
108
109     /**
110      * Setup this transformer
111      *
112      * @param resolver a {@link SourceResolver} instance
113      * @param objectModel the objectModel
114      * @param src <code>src</code> parameter
115      * @param parameters optional parameters
116      * @exception ProcessingException if an error occurs
117      * @exception SAXException if an error occurs
118      * @exception IOException if an error occurs
119      */

120     public void setup(SourceResolver resolver, Map JavaDoc objectModel,
121                       String JavaDoc src, Parameters parameters)
122         throws ProcessingException, SAXException JavaDoc, IOException JavaDoc {
123
124         super.setup(resolver, objectModel, src, parameters);
125
126         // setup the jpath transformer for this thread
127
Object JavaDoc bean = FlowHelper.getContextObject(objectModel);
128         m_kont = FlowHelper.getWebContinuation(objectModel);
129         m_jxpathContext = JXPathContext.newContext(bean);
130     }
131
132     /**
133      * Intercept startElement to ensure all &lt;jpath:action&gt; attributes
134      * are modified.
135      *
136      * @param uri a <code>String</code> value
137      * @param loc a <code>String</code> value
138      * @param raw a <code>String</code> value
139      * @param a an <code>Attributes</code> value
140      * @exception SAXException if an error occurs
141      */

142     public void startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc a)
143         throws SAXException JavaDoc {
144
145         AttributesImpl JavaDoc impl = new AttributesImpl JavaDoc(a);
146         checkJPathAction(impl);
147
148         super.startElement(uri, loc, raw, impl);
149     }
150
151     /**
152      * Entry method for all elements in our namespace
153      *
154      * @param uri a <code>String</code> value
155      * @param name a <code>String</code> value
156      * @param raw a <code>String</code> value
157      * @param attr an <code>Attributes</code> value
158      * @exception ProcessingException if an error occurs
159      * @exception IOException if an error occurs
160      * @exception SAXException if an error occurs
161      */

162     public void startTransformingElement(
163         String JavaDoc uri, String JavaDoc name, String JavaDoc raw, Attributes JavaDoc attr
164     )
165         throws ProcessingException ,IOException JavaDoc, SAXException JavaDoc {
166
167         if (JPATH_VALUEOF.equals(name)) {
168             doValueOf(attr);
169         } else if (JPATH_CONTINUATION.equals(name)) {
170             doContinuation(attr);
171         } else if (JPATH_IF.equals(name)) {
172             doIf(attr);
173         } else {
174             super.startTransformingElement(uri, name, raw, attr);
175         }
176     }
177
178     /**
179      * Exit method for all elements in our namespace
180      *
181      * @param uri a <code>String</code> value
182      * @param name a <code>String</code> value
183      * @param raw a <code>String</code> value
184      * @exception ProcessingException if an error occurs
185      * @exception IOException if an error occurs
186      * @exception SAXException if an error occurs
187      */

188     public void endTransformingElement(
189         String JavaDoc uri, String JavaDoc name, String JavaDoc raw
190     )
191         throws ProcessingException, IOException JavaDoc, SAXException JavaDoc {
192
193         if (JPATH_VALUEOF.equals(name) ||
194             JPATH_CONTINUATION.equals(name)) {
195             return; // do nothing
196
} else if (JPATH_IF.equals(name)) {
197             finishIf();
198         } else {
199             super.endTransformingElement(uri, name, raw);
200         }
201     }
202
203     /**
204      * Helper method to check for the existance of an attribute named
205      * jpath:action. If existing the string 'id' is replaced with the
206      * continuation id.
207      *
208      * @param a an {@link AttributesImpl} instance
209      */

210     private void checkJPathAction(final AttributesImpl JavaDoc a) {
211
212         // check for jpath:action attribute
213
int idx = a.getIndex(JPATH_ACTION);
214
215         if (idx != -1 && JPATH_NAMESPACE_URI.equals(a.getURI(idx))) {
216             if (getLogger().isDebugEnabled()) {
217                 getLogger().debug("found jpath:action, adjusting");
218             }
219
220             String JavaDoc value = a.getValue(idx);
221
222             // REVISIT(MC): support for continuation level
223
String JavaDoc id = m_kont.getContinuation(0).getId();
224
225             a.removeAttribute(idx);
226             a.addAttribute(
227                 "", "action", "action", "CDATA", m_re.subst(value, id)
228             );
229         }
230     }
231
232     /**
233      * Helper method for obtaining the value of a particular variable.
234      *
235      * @param variable variable name
236      * @return variable value as an <code>Object</code>
237      */

238     private Object JavaDoc getValue(final String JavaDoc variable) {
239
240         Object JavaDoc value;
241
242         if (m_cache.containsKey(variable)) {
243             value = m_cache.get(variable);
244         } else {
245             value = JXPathContext.compile(variable).getValue(m_jxpathContext);
246
247             if (value == null) {
248                 if (getLogger().isWarnEnabled()) {
249                     final String JavaDoc msg =
250                         "Value for jpath variable '" + variable + "' does not exist";
251                     getLogger().warn(msg);
252                 }
253             }
254
255             m_cache.put(variable, value);
256         }
257
258         return value;
259     }
260
261     /**
262      * Helper method to process a &lt;jpath:value-of select="."&gt; tag
263      *
264      * @param a an {@link Attributes} instance
265      * @exception SAXException if a SAX error occurs
266      * @exception ProcessingException if a processing error occurs
267      */

268     private void doValueOf(final Attributes JavaDoc a)
269         throws SAXException JavaDoc, ProcessingException {
270
271         final String JavaDoc select = a.getValue(JPATH_VALUEOF_SELECT);
272
273         if (null != select) {
274             sendTextEvent((String JavaDoc)getValue(select));
275         } else {
276             throw new ProcessingException(
277                 "jpath:" + JPATH_VALUEOF + " specified without a select attribute"
278             );
279         }
280     }
281
282     /**
283      * Helper method to process a &lt;jpath:continuation select=""/&gt; element.
284      *
285      * @param a an <code>Attributes</code> value
286      * @exception SAXException if an error occurs
287      */

288     private void doContinuation(final Attributes JavaDoc a)
289         throws SAXException JavaDoc {
290
291         final String JavaDoc level = a.getValue(JPATH_CONTINUATION_SELECT);
292
293         final String JavaDoc id = (level != null)
294             ? m_kont.getContinuation(Integer.decode(level).intValue()).getId()
295             : m_kont.getContinuation(0).getId();
296
297         sendTextEvent(id);
298     }
299
300     /**
301      * Helper method to process a &lt;jpath:if test="..."&gt; element.
302      *
303      * @param a an <code>Attributes</code> value
304      * @exception SAXException if an error occurs
305      */

306     private void doIf(final Attributes JavaDoc a)
307         throws SAXException JavaDoc {
308
309         // handle nested jpath:if statements, if ignoreEventsCount is > 0, then
310
// we are processing a nested jpath:if statement for which the parent
311
// jpath:if test resulted in a false (ie. disallow subelements) result.
312

313         if (ignoreEventsCount > 0) {
314             ++ignoreEventsCount;
315             return;
316         }
317
318         // get the test variable
319
final Object JavaDoc value = getValue(a.getValue(JPATH_TEST));
320
321         final boolean isTrueBoolean =
322             value instanceof Boolean JavaDoc && ((Boolean JavaDoc)value).booleanValue() == true;
323         final boolean isNonNullNonBoolean =
324             value != null && !(value instanceof Boolean JavaDoc);
325
326         if (isTrueBoolean || isNonNullNonBoolean) {
327             // do nothing, allow all subelements
328
if (getLogger().isDebugEnabled()) {
329                 getLogger().debug("jpath:if results in allowing subelements");
330             }
331         } else {
332             // disallow all subelements
333
if (getLogger().isDebugEnabled()) {
334                 getLogger().debug("jpath:if results in disallowing subelements");
335             }
336             ++ignoreEventsCount;
337         }
338     }
339
340     /**
341      * Helper method to process a &lt;/jpath:if&gt; element.
342      *
343      * @exception SAXException if an error occurs
344      */

345     private void finishIf()
346         throws SAXException JavaDoc {
347
348         // end recording (and dump resulting document fragment) if we've reached
349
// the closing jpath:if tag for which the recording was started.
350
if (ignoreEventsCount > 0) {
351             --ignoreEventsCount;
352         }
353
354         if (getLogger().isDebugEnabled()) {
355             getLogger().debug("jpath:if closed");
356         }
357     }
358
359     /**
360      * Release all held resources.
361      */

362     public void recycle() {
363         m_cache.clear();
364         m_kont = null;
365         m_jxpathContext = null;
366
367         super.recycle();
368     }
369 }
370
Popular Tags