KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > treeprocessor > sitemap > SitemapLanguage


1 /*
2  * Copyright 1999-2004 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.components.treeprocessor.sitemap;
17
18 import java.util.Arrays JavaDoc;
19 import java.util.Collection JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.HashSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Set JavaDoc;
26
27 import org.apache.avalon.excalibur.logger.LoggerManager;
28 import org.apache.avalon.framework.component.ComponentManager;
29 import org.apache.avalon.framework.configuration.Configuration;
30 import org.apache.avalon.framework.configuration.ConfigurationException;
31 import org.apache.avalon.framework.configuration.DefaultConfiguration;
32 import org.apache.cocoon.components.CocoonComponentManager;
33 import org.apache.cocoon.components.treeprocessor.CategoryNode;
34 import org.apache.cocoon.components.treeprocessor.CategoryNodeBuilder;
35 import org.apache.cocoon.components.treeprocessor.DefaultTreeBuilder;
36 import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
37 import org.apache.cocoon.generation.Generator;
38 import org.apache.cocoon.serialization.Serializer;
39 import org.apache.cocoon.sitemap.PatternException;
40 import org.apache.cocoon.sitemap.SitemapComponentSelector;
41 import org.apache.cocoon.util.StringUtils;
42 import org.apache.regexp.RE;
43
44 /**
45  * The tree builder for the sitemap language.
46  *
47  * @author <a HREF="mailto:sylvain@apache.org">Sylvain Wallez</a>
48  * @version CVS $Id: SitemapLanguage.java 30932 2004-07-29 17:35:38Z vgritsenko $
49  */

50
51 public class SitemapLanguage extends DefaultTreeBuilder {
52
53     // Regexp's for splitting expressions
54
private static final String JavaDoc COMMA_SPLIT_REGEXP = "[\\s]*,[\\s]*";
55     private static final String JavaDoc EQUALS_SPLIT_REGEXP = "[\\s]*=[\\s]*";
56
57     /**
58      * Build a component manager with the contents of the &lt;map:components&gt; element of
59      * the tree.
60      */

61     protected ComponentManager createComponentManager(Configuration tree) throws Exception JavaDoc {
62
63         // Get the map:component node
64
// Don't check namespace here : this will be done by node builders
65
Configuration config = tree.getChild("components", false);
66
67         if (config == null) {
68             if (getLogger().isDebugEnabled()) {
69                 getLogger().debug("Sitemap has no components definition at " + tree.getLocation());
70             }
71             config = new DefaultConfiguration("", "");
72         }
73         
74         final CocoonComponentManager manager = new CocoonComponentManager(this.parentManager);
75         
76         manager.enableLogging(getLogger());
77         
78         final LoggerManager loggerManager = (LoggerManager) this.parentManager.lookup(LoggerManager.ROLE);
79         manager.setLoggerManager(loggerManager);
80
81         if (null != this.context ) {
82             manager.contextualize(this.context);
83         }
84
85         if (null != this.roleManager) {
86             manager.setRoleManager(this.roleManager);
87         }
88
89         manager.configure(config);
90         manager.initialize();
91
92         return manager;
93     }
94
95     //---- Views management
96

97     /** Collection of view names for each label */
98     private Map JavaDoc labelViews = new HashMap JavaDoc();
99
100     /** The views CategoryNode */
101     private CategoryNode viewsNode;
102
103     /** Are we currently building a view ? */
104     private boolean isBuildingView = false;
105
106     /** Are we currently building a view ? */
107     private boolean isBuildingErrorHandler = false;
108
109     /**
110      * Pseudo-label for views <code>from-position="first"</code> (i.e. generator).
111      */

112     public static final String JavaDoc FIRST_POS_LABEL = "!first!";
113
114     /**
115      * Pseudo-label for views <code>from-position="last"</code> (i.e. serializer).
116      */

117     public static final String JavaDoc LAST_POS_LABEL = "!last!";
118
119     public void recycle() {
120         super.recycle();
121
122         // Go back to initial state
123
this.labelViews.clear();
124         this.viewsNode = null;
125         this.isBuildingView = false;
126         this.isBuildingErrorHandler = false;
127     }
128
129     /**
130      * Set to <code>true</code> while building the internals of a &lt;map:view&gt;
131      */

132     public void setBuildingView(boolean building) {
133         this.isBuildingView = building;
134     }
135
136     /**
137      * Are we currently building a view ?
138      */

139     public boolean isBuildingView() {
140         return this.isBuildingView;
141     }
142
143     /**
144      * Set to <code>true</code> while building the internals of a &lt;map:handle-errors&gt;
145      */

146     public void setBuildingErrorHandler(boolean building) {
147         this.isBuildingErrorHandler = building;
148     }
149
150     /**
151      * Are we currently building an error handler ?
152      */

153     public boolean isBuildingErrorHandler() {
154         return this.isBuildingErrorHandler;
155     }
156
157     /**
158      * Add a view for a label. This is used to register all views that start from
159      * a given label.
160      *
161      * @param label the label (or pseudo-label) for the view
162      * @param view the view name
163      */

164     public void addViewForLabel(String JavaDoc label, String JavaDoc view) {
165         if (getLogger().isDebugEnabled()) {
166             getLogger().debug("views:addViewForLabel(" + label + ", " + view + ")");
167         }
168         Set JavaDoc views = (Set JavaDoc)this.labelViews.get(label);
169         if (views == null) {
170             views = new HashSet JavaDoc();
171             this.labelViews.put(label, views);
172         }
173
174         views.add(view);
175     }
176
177     /**
178      * Get the names of views for a given statement. If the cocoon view exists in the returned
179      * collection, the statement can directly branch to the view-handling node.
180      *
181      * @param role the component role (e.g. <code>Generator.ROLE</code>)
182      * @param hint the component hint, i.e. the 'type' attribute
183      * @param statement the sitemap statement
184      * @return the view names for this statement
185      */

186     public Collection JavaDoc getViewsForStatement(String JavaDoc role, String JavaDoc hint, Configuration statement) throws Exception JavaDoc {
187
188         String JavaDoc statementLabels = statement.getAttribute("label", null);
189
190         if (this.isBuildingView) {
191             // Labels are forbidden inside view definition
192
if (statementLabels != null) {
193                 String JavaDoc msg = "Cannot put a 'label' attribute inside view definition at " + statement.getLocation();
194                 throw new ConfigurationException(msg);
195             }
196
197             // We are currently building a view. Don't recurse !
198
return null;
199         }
200
201         // Compute the views attached to this component
202
Set JavaDoc views = null;
203
204         // Build the set for all labels for this statement
205
Set JavaDoc labels = new HashSet JavaDoc();
206
207         // 1 - labels defined on the component
208
if (role != null && role.length() > 0) {
209             SitemapComponentSelector selector = null;
210             try {
211                 selector = (SitemapComponentSelector)this.manager.lookup(role + "Selector");
212                 String JavaDoc[] compLabels = selector.getLabels(hint);
213                 if (compLabels != null) {
214                     for (int i = 0; i < compLabels.length; i++) {
215                         labels.add(compLabels[i]);
216                     }
217                 }
218             } catch(Exception JavaDoc e) {
219                 // Ignore (no selector for this role)
220
getLogger().warn("No selector for role " + role);
221             } finally {
222                 this.manager.release( selector );
223             }
224         }
225
226         // 2 - labels defined on this statement
227
if (statementLabels != null) {
228             labels.addAll(splitLabels(statementLabels));
229         }
230
231         // 3 - pseudo-label depending on the role
232
if (Generator.ROLE.equals(role)) {
233             labels.add("!first!");
234         } else if (Serializer.ROLE.equals(role)) {
235             labels.add("!last!");
236         }
237
238         // Build the set of views attached to these labels
239
views = new HashSet JavaDoc();
240
241         // Iterate on all labels for this statement
242
Iterator JavaDoc labelIter = labels.iterator();
243         while(labelIter.hasNext()) {
244
245             // Iterate on all views for this labek
246
Collection JavaDoc coll = (Collection JavaDoc)this.labelViews.get(labelIter.next());
247             if (coll != null) {
248                 Iterator JavaDoc viewIter = coll.iterator();
249                 while(viewIter.hasNext()) {
250                     String JavaDoc viewName = (String JavaDoc)viewIter.next();
251
252                     views.add(viewName);
253                 }
254             }
255         }
256
257         // Don't keep empty result
258
if (views.size() == 0) {
259             views = null;
260
261             if (getLogger().isDebugEnabled()) {
262                 getLogger().debug(statement.getName() + " has no views at " + statement.getLocation());
263             }
264         } else {
265             if (getLogger().isDebugEnabled()) {
266                 // Dump matching views
267
StringBuffer JavaDoc buf = new StringBuffer JavaDoc(statement.getName() + " will match views [");
268                 Iterator JavaDoc iter = views.iterator();
269                 while(iter.hasNext()) {
270                     buf.append(iter.next()).append(" ");
271                 }
272                 buf.append("] at ").append(statement.getLocation());
273
274                 getLogger().debug(buf.toString());
275             }
276         }
277
278         return views;
279     }
280
281     /**
282      * Before linking nodes, lookup the view category node used in {@link #getViewNodes(Collection)}.
283      */

284     protected void linkNodes() throws Exception JavaDoc {
285         // Get the views category node
286
this.viewsNode = CategoryNodeBuilder.getCategoryNode(this, "views");
287
288         super.linkNodes();
289     }
290
291     /**
292      * Get the {view name, view node} map for a collection of view names.
293      * This allows to resolve view nodes at build time, thus avoiding runtime lookup.
294      *
295      * @param viewNames the view names
296      * @return association of names to views
297      */

298     public Map JavaDoc getViewNodes(Collection JavaDoc viewNames) throws Exception JavaDoc {
299         if (viewNames == null || viewNames.size() == 0) {
300             return null;
301         }
302
303         if (this.viewsNode == null) {
304             return null;
305         }
306
307         Map JavaDoc result = new HashMap JavaDoc();
308
309         Iterator JavaDoc iter = viewNames.iterator();
310         while(iter.hasNext()) {
311             String JavaDoc viewName = (String JavaDoc)iter.next();
312             result.put(viewName, viewsNode.getNodeByName(viewName));
313         }
314
315         return result;
316     }
317     
318     /**
319      * Extract pipeline-hints from the given statement (if any exist)
320      *
321      * @param role the component role (e.g. <code>Generator.ROLE</code>)
322      * @param hint the component hint, i.e. the 'type' attribute
323      * @param statement the sitemap statement
324      * @return the hint params <code>Map</code> for this statement, or null
325      * if none exist
326      */

327     public Map JavaDoc getHintsForStatement(String JavaDoc role, String JavaDoc hint, Configuration statement) throws Exception JavaDoc {
328         // This method implemets the hintParam Syntax as follows:
329
// A hints attribute has one or more comma separated hints
330
// hints-attr :: hint [ ',' hint ]*
331
// A hint is a name and an optional (string) value
332
// If there is no value, it is considered as boolean string "true"
333
// hint :: literal [ '=' litteral ]
334
// literal :: <a character string where the chars ',' and '=' are not permitted>
335
//
336
// A ConfigurationException is thrown if there is a problem "parsing"
337
// the hint.
338

339         String JavaDoc statementHintParams = statement.getAttribute("pipeline-hints", null);
340         String JavaDoc componentHintParams = null;
341         String JavaDoc hintParams = null;
342
343         // firstly, determine if any pipeline-hints are defined at the component level
344
// if so, inherit these pipeline-hints (these hints can be overriden by local pipeline-hints)
345
SitemapComponentSelector selector = null;
346         try {
347             selector = (SitemapComponentSelector)this.manager.lookup(role + "Selector");
348             componentHintParams = selector.getPipelineHint(hint);
349         } catch (Exception JavaDoc ex) {
350             if (getLogger().isWarnEnabled()) {
351                 getLogger().warn("pipeline-hints: Component Exception: could not " +
352                              "check for component level hints " + ex);
353             }
354         } finally {
355             this.manager.release(selector);
356         }
357
358         if (componentHintParams != null) {
359             hintParams = componentHintParams;
360
361             if (statementHintParams != null) {
362                 hintParams = hintParams + "," + statementHintParams;
363             }
364         } else {
365             hintParams = statementHintParams;
366         }
367
368         // if there are no pipeline-hints defined then
369
// it makes no sense to continue so, return null
370
if (hintParams == null) {
371             return null;
372         }
373
374         Map JavaDoc params = new HashMap JavaDoc();
375
376         RE commaSplit = new RE(COMMA_SPLIT_REGEXP);
377         RE equalsSplit = new RE(EQUALS_SPLIT_REGEXP);
378
379         String JavaDoc[] expressions = commaSplit.split(hintParams.trim());
380
381         if (getLogger().isDebugEnabled()) {
382             getLogger().debug("pipeline-hints: (aggregate-hint) " + hintParams);
383         }
384
385         for (int i=0; i<expressions.length;i++) {
386             String JavaDoc [] nameValuePair = equalsSplit.split(expressions[i]);
387
388             try {
389                 if (nameValuePair.length < 2) {
390                     if (getLogger().isDebugEnabled()) {
391                         getLogger().debug("pipeline-hints: (name) " + nameValuePair[0]
392                                        + "\npipeline-hints: (value) [implicit] true");
393                     }
394   
395                     params.put( VariableResolverFactory.getResolver(nameValuePair[0], this.manager),
396                                 VariableResolverFactory.getResolver("true", this.manager));
397                 } else {
398                     if (getLogger().isDebugEnabled()) {
399                         getLogger().debug("pipeline-hints: (name) " + nameValuePair[0]
400                                           + "\npipeline-hints: (value) " + nameValuePair[1]);
401                     }
402   
403                     params.put( VariableResolverFactory.getResolver(nameValuePair[0], this.manager),
404                                 VariableResolverFactory.getResolver(nameValuePair[1], this.manager));
405                 }
406             } catch(PatternException pe) {
407                 String JavaDoc msg = "Invalid pattern '" + hintParams + "' at " + statement.getLocation();
408                 getLogger().error(msg, pe);
409                 throw new ConfigurationException(msg, pe);
410             }
411         }
412
413         return params;
414     }
415
416     /**
417      * Split a list of space/comma separated labels into a Collection
418      *
419      * @return the collection of labels (may be empty, nut never null)
420      */

421     private static final Collection JavaDoc splitLabels(String JavaDoc labels) {
422         if (labels == null) {
423             return Collections.EMPTY_SET;
424         } else {
425             return Arrays.asList(StringUtils.split(labels, ", \t\n\r"));
426         }
427     }
428 }
429
Popular Tags