KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > treeprocessor > TreeProcessor


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;
17
18 import java.util.Map JavaDoc;
19
20 import org.apache.avalon.excalibur.component.RoleManageable;
21 import org.apache.avalon.excalibur.component.RoleManager;
22 import org.apache.avalon.framework.activity.Disposable;
23 import org.apache.avalon.framework.component.ComponentException;
24 import org.apache.avalon.framework.component.ComponentManager;
25 import org.apache.avalon.framework.component.Composable;
26 import org.apache.avalon.framework.component.Recomposable;
27 import org.apache.avalon.framework.configuration.Configurable;
28 import org.apache.avalon.framework.configuration.Configuration;
29 import org.apache.avalon.framework.configuration.ConfigurationException;
30 import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
31 import org.apache.avalon.framework.container.ContainerUtil;
32 import org.apache.avalon.framework.context.Context;
33 import org.apache.avalon.framework.context.ContextException;
34 import org.apache.avalon.framework.context.Contextualizable;
35 import org.apache.avalon.framework.logger.AbstractLogEnabled;
36 import org.apache.avalon.framework.thread.ThreadSafe;
37 import org.apache.cocoon.Processor;
38 import org.apache.cocoon.components.CocoonComponentManager;
39 import org.apache.cocoon.components.ExtendedComponentSelector;
40 import org.apache.cocoon.components.LifecycleHelper;
41 import org.apache.cocoon.components.pipeline.ProcessingPipeline;
42 import org.apache.cocoon.components.source.SourceUtil;
43 import org.apache.cocoon.components.source.impl.DelayedRefreshSourceWrapper;
44 import org.apache.cocoon.environment.Environment;
45 import org.apache.excalibur.source.Source;
46 import org.apache.excalibur.source.SourceResolver;
47
48 /**
49  * Interpreted tree-traversal implementation of a pipeline assembly language.
50  *
51  * @author <a HREF="mailto:sylvain@apache.org">Sylvain Wallez</a>
52  * @version CVS $Id: TreeProcessor.java 312595 2005-10-10 09:59:56Z cziegeler $
53  */

54
55 public class TreeProcessor
56     extends AbstractLogEnabled
57     implements ThreadSafe,
58                Processor,
59                Composable,
60                Configurable,
61                RoleManageable,
62                Contextualizable,
63                Disposable {
64
65     public static final String JavaDoc COCOON_REDIRECT_ATTR = "sitemap:cocoon-redirect";
66
67     private static final String JavaDoc XCONF_URL =
68         "resource://org/apache/cocoon/components/treeprocessor/treeprocessor-builtins.xml";
69
70     /** The parent TreeProcessor, if any */
71     protected TreeProcessor parent;
72
73     /** The context */
74     protected Context context;
75
76     /** The component manager */
77     protected ComponentManager manager;
78
79     /** The role manager */
80     protected RoleManager roleManager;
81
82     /** Selector of TreeBuilders, the hint is the language name */
83     protected ExtendedComponentSelector builderSelector;
84
85     /** Last modification time */
86     protected long lastModified = 0;
87
88     /** The source of the tree definition */
89     protected DelayedRefreshSourceWrapper source;
90
91     /** Delay for <code>sourceLastModified</code>. */
92     protected long lastModifiedDelay;
93
94     /** The current language configuration */
95     protected Configuration currentLanguage;
96
97     /** Check for reload? */
98     protected boolean checkReload;
99
100     /** The source resolver */
101     protected SourceResolver resolver;
102
103     /** The actual processor (package-private as needs to be accessed by ConcreteTreeProcessor) */
104     ConcreteTreeProcessor concreteProcessor;
105
106     /**
107      * Create a TreeProcessor.
108      */

109     public TreeProcessor() {
110         this.checkReload = true;
111         this.lastModifiedDelay = 1000;
112     }
113
114     /**
115      * Create a child processor for a given language
116      */

117     protected TreeProcessor(TreeProcessor parent, ComponentManager manager) {
118         this.parent = parent;
119
120         // Copy all that can be copied from the parent
121
this.enableLogging(parent.getLogger());
122         this.context = parent.context;
123         this.roleManager = parent.roleManager;
124         this.builderSelector = parent.builderSelector;
125         this.checkReload = parent.checkReload;
126         this.lastModifiedDelay = parent.lastModifiedDelay;
127
128         // We have our own CM
129
this.manager = manager;
130     }
131
132     /**
133      * Create a new child of this processor (used for mounting submaps).
134      *
135      * @param manager the component manager to be used by the child processor.
136      * @return a new child processor.
137      */

138     public TreeProcessor createChildProcessor(ComponentManager manager,
139                                               String JavaDoc actualSource,
140                                               boolean checkReload)
141     throws Exception JavaDoc {
142
143         // Note: lifecycle methods aren't called, since this constructors copies all
144
// that can be copied from the parent (see above)
145
TreeProcessor child = new TreeProcessor(this, manager);
146         child.checkReload = checkReload;
147         child.resolver = (SourceResolver)manager.lookup(SourceResolver.ROLE);
148         child.source = new DelayedRefreshSourceWrapper(child.resolver.resolveURI(actualSource), lastModifiedDelay);
149         
150         return child;
151     }
152
153     /* (non-Javadoc)
154      * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
155      */

156     public void contextualize(Context context) throws ContextException {
157         this.context = context;
158     }
159
160     /* (non-Javadoc)
161      * @see org.apache.avalon.framework.component.Composable#compose(org.apache.avalon.framework.component.ComponentManager)
162      */

163     public void compose(ComponentManager manager) throws ComponentException {
164         this.manager = manager;
165         this.resolver = (SourceResolver)this.manager.lookup(SourceResolver.ROLE);
166     }
167
168     /* (non-Javadoc)
169      * @see org.apache.avalon.excalibur.component.RoleManageable#setRoleManager(org.apache.avalon.excalibur.component.RoleManager)
170      */

171     public void setRoleManager(RoleManager rm) {
172         this.roleManager = rm;
173     }
174
175
176 /*
177   <processor>
178     <reload delay="10"/>
179     <language>...</language>
180   </processor>
181 */

182     public void configure(Configuration config)
183     throws ConfigurationException {
184
185         this.checkReload = config.getAttributeAsBoolean("check-reload", true);
186
187         // Obtain the configuration file, or use the XCONF_URL if none
188
// is defined
189
String JavaDoc xconfURL = config.getAttribute("config", XCONF_URL);
190
191         // Reload check delay. Default is 1 second.
192
this.lastModifiedDelay = config.getChild("reload").getAttributeAsLong("delay", 1000L);
193
194         String JavaDoc fileName = config.getAttribute("file", "sitemap.xmap");
195         
196         try {
197             this.source = new DelayedRefreshSourceWrapper(this.resolver.resolveURI(fileName), lastModifiedDelay);
198         } catch (Exception JavaDoc e) {
199             throw new ConfigurationException("Cannot resolve " + fileName, e);
200         }
201
202         // Read the builtin languages definition file
203
Configuration builtin;
204         try {
205             Source source = this.resolver.resolveURI(xconfURL);
206             try {
207                 SAXConfigurationHandler handler = new SAXConfigurationHandler();
208                 SourceUtil.toSAX( this.manager, source, null, handler);
209                 builtin = handler.getConfiguration();
210             } finally {
211                 this.resolver.release(source);
212             }
213         } catch(Exception JavaDoc e) {
214             String JavaDoc msg = "Error while reading " + xconfURL + ": " + e.getMessage();
215             throw new ConfigurationException(msg, e);
216         }
217
218         // Create a selector for tree builders of all languages
219
this.builderSelector = new ExtendedComponentSelector(Thread.currentThread().getContextClassLoader());
220         try {
221             LifecycleHelper.setupComponent(this.builderSelector,
222                                            getLogger(),
223                                            this.context,
224                                            this.manager,
225                                            this.roleManager,
226                                            builtin);
227         } catch (ConfigurationException e) {
228             throw e;
229         } catch (Exception JavaDoc e) {
230             throw new ConfigurationException("Could not setup builder selector", e);
231         }
232     }
233
234     /**
235      * Process the given <code>Environment</code> producing the output.
236      * @return If the processing is successfull <code>true</code> is returned.
237      * If not match is found in the sitemap <code>false</code>
238      * is returned.
239      * @throws org.apache.cocoon.ResourceNotFoundException If a sitemap component tries
240      * to access a resource which can not
241      * be found, e.g. the generator
242      * ConnectionResetException If the connection was reset
243      */

244     public boolean process(Environment environment) throws Exception JavaDoc {
245
246         this.setupConcreteProcessor(environment);
247
248         return this.concreteProcessor.process(environment);
249     }
250
251     /**
252      * Process the given <code>Environment</code> to assemble
253      * a <code>ProcessingPipeline</code>.
254      * @since 2.1
255      */

256     public ProcessingPipeline buildPipeline(Environment environment)
257     throws Exception JavaDoc {
258
259             setupConcreteProcessor(environment);
260
261             return this.concreteProcessor.buildPipeline(environment);
262     }
263
264     /* (non-Javadoc)
265      * @see org.apache.cocoon.Processor#getRootProcessor()
266      */

267     public Processor getRootProcessor() {
268         TreeProcessor result = this;
269         while(result.parent != null) {
270             result = result.parent;
271         }
272
273         return result;
274     }
275
276     /**
277      * Set the sitemap component configurations
278      */

279     public void setComponentConfigurations(Configuration componentConfigurations) {
280         this.concreteProcessor.setComponentConfigurations(componentConfigurations);
281     }
282
283     /* (non-Javadoc)
284      * @see org.apache.cocoon.Processor#getComponentConfigurations()
285      */

286     public Map JavaDoc getComponentConfigurations() {
287         return this.concreteProcessor.getComponentConfigurations();
288     }
289
290     private void setupConcreteProcessor(Environment env) throws Exception JavaDoc {
291         
292         if (this.parent == null) {
293             // Ensure root sitemap uses the correct context, even if not located in the webapp context
294
env.changeContext("", this.source.getURI());
295         }
296
297         // check for sitemap changes
298
if (this.concreteProcessor == null ||
299             (this.checkReload && this.source.getLastModified() != this.lastModified)) {
300             buildConcreteProcessor(env);
301         }
302     }
303
304     private synchronized void buildConcreteProcessor(Environment env) throws Exception JavaDoc {
305
306         // Now that we entered the synchronized area, recheck what's already
307
// been checked in process().
308
if (this.concreteProcessor != null && source.getLastModified() == this.lastModified) {
309             // Nothing changed
310
return;
311         }
312
313         long startTime = System.currentTimeMillis();
314
315         // Dispose the old processor, if any
316
if (this.concreteProcessor != null) {
317             this.concreteProcessor.markForDisposal();
318         }
319
320         // Get a builder
321
TreeBuilder builder = (TreeBuilder)this.builderSelector.select("sitemap");
322         ConcreteTreeProcessor newProcessor = new ConcreteTreeProcessor(this);
323         long newLastModified;
324         this.setupLogger(newProcessor);
325         //FIXME (SW): why do we need to enterProcessor here?
326
CocoonComponentManager.enterEnvironment(env, this.manager, this);
327         try {
328             if (builder instanceof Recomposable) {
329                 ((Recomposable)builder).recompose(this.manager);
330             }
331             builder.setProcessor(newProcessor);
332             
333             newLastModified = this.source.getLastModified();
334
335             ProcessingNode root = builder.build(this.source);
336
337             newProcessor.setProcessorData(builder.getSitemapComponentManager(), root, builder.getDisposableNodes());
338         } finally {
339             CocoonComponentManager.leaveEnvironment();
340             this.builderSelector.release(builder);
341         }
342
343         if (getLogger().isDebugEnabled()) {
344             double time = (this.lastModified - startTime) / 1000.0;
345             getLogger().debug("TreeProcessor built in " + time + " secs from " + source.getURI());
346         }
347
348         // Switch to the new processor (ensure it's never temporarily null)
349
this.concreteProcessor = newProcessor;
350         this.lastModified = newLastModified;
351     }
352
353     /* (non-Javadoc)
354      * @see org.apache.avalon.framework.activity.Disposable#dispose()
355      */

356     public void dispose() {
357         // Dispose the concrete processor. No need to check for existing requests, as there
358
// are none when a TreeProcessor is disposed.
359
ContainerUtil.dispose(this.concreteProcessor);
360         this.concreteProcessor = null;
361
362         if (this.manager != null) {
363             if (this.source != null) {
364                 this.resolver.release(this.source.getSource());
365                 this.source = null;
366             }
367
368             if (this.parent == null) {
369                 // root processor : dispose the builder selector
370
this.builderSelector.dispose();
371                 this.builderSelector = null;
372             }
373
374             // Release resolver looked up in compose()
375
this.manager.release(this.resolver);
376             this.resolver = null;
377
378             this.manager = null;
379         }
380     }
381     
382     public String JavaDoc toString() {
383         return "TreeProcessor - " + (source == null ? "[unknown location]" : source.getURI());
384     }
385 }
386
Popular Tags