KickJava   Java API By Example, From Geeks To Geeks.

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


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.components.treeprocessor;
17
18 import java.io.IOException JavaDoc;
19 import java.net.MalformedURLException JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24
25 import org.apache.avalon.framework.activity.Disposable;
26 import org.apache.avalon.framework.component.ComponentManager;
27 import org.apache.avalon.framework.configuration.Configuration;
28 import org.apache.avalon.framework.logger.AbstractLogEnabled;
29 import org.apache.avalon.framework.logger.Logger;
30 import org.apache.cocoon.ProcessingException;
31 import org.apache.cocoon.Processor;
32 import org.apache.cocoon.components.ChainedConfiguration;
33 import org.apache.cocoon.components.CocoonComponentManager;
34 import org.apache.cocoon.components.pipeline.ProcessingPipeline;
35 import org.apache.cocoon.environment.Environment;
36 import org.apache.cocoon.environment.ForwardRedirector;
37 import org.apache.cocoon.environment.Redirector;
38 import org.apache.cocoon.environment.wrapper.EnvironmentWrapper;
39 import org.apache.cocoon.environment.wrapper.MutableEnvironmentFacade;
40
41 /**
42  * The concrete implementation of {@link Processor}, containing the evaluation tree and associated
43  * data such as component manager.
44  *
45  * @version $Id: ConcreteTreeProcessor.java 202255 2005-06-28 17:45:25Z vgritsenko $
46  */

47 public class ConcreteTreeProcessor extends AbstractLogEnabled
48                                    implements Processor, Disposable {
49
50     /** The processor that wraps us */
51     private TreeProcessor wrappingProcessor;
52
53     /** Component manager defined by the <map:components> of this sitemap */
54     ComponentManager sitemapComponentManager;
55
56     /** Processing nodes that need to be disposed with this processor */
57     private List JavaDoc disposableNodes;
58
59     /** Root node of the processing tree */
60     private ProcessingNode rootNode;
61
62     private Map JavaDoc sitemapComponentConfigurations;
63
64     private Configuration componentConfigurations;
65
66     /** Number of simultaneous uses of this processor (either by concurrent request or by internal requests) */
67     private int requestCount;
68
69     /** Builds a concrete processig, given the wrapping processor */
70     public ConcreteTreeProcessor(TreeProcessor wrappingProcessor) {
71         this.wrappingProcessor = wrappingProcessor;
72     }
73
74     /** Set the processor data, result of the treebuilder job */
75     public void setProcessorData(ComponentManager manager, ProcessingNode rootNode, List JavaDoc disposableNodes) {
76         if (this.sitemapComponentManager != null) {
77             throw new IllegalStateException JavaDoc("setProcessorData() can only be called once");
78         }
79
80         this.sitemapComponentManager = manager;
81         this.rootNode = rootNode;
82         this.disposableNodes = disposableNodes;
83     }
84
85     /** Set the sitemap component configurations (called as part of the tree building process) */
86     public void setComponentConfigurations(Configuration componentConfigurations) {
87         this.componentConfigurations = componentConfigurations;
88         this.sitemapComponentConfigurations = null;
89     }
90
91     /**
92      * Get the sitemap component configurations
93      * @since 2.1
94      */

95     public Map JavaDoc getComponentConfigurations() {
96         // do we have the sitemap configurations prepared for this processor?
97
if ( null == this.sitemapComponentConfigurations ) {
98
99             synchronized (this) {
100
101                 if ( this.sitemapComponentConfigurations == null ) {
102                     // do we have configurations?
103
final Configuration[] childs = (this.componentConfigurations == null
104                                                      ? null
105                                                      : this.componentConfigurations.getChildren());
106
107                     if ( null != childs ) {
108
109                         if ( null == this.wrappingProcessor.parent ) {
110                             this.sitemapComponentConfigurations = new HashMap JavaDoc(12);
111                         } else {
112                             // copy all configurations from parent
113
this.sitemapComponentConfigurations = new HashMap JavaDoc(
114                                         this.wrappingProcessor.parent.getComponentConfigurations());
115                         }
116
117                         // and now check for new configurations
118
for(int m = 0; m < childs.length; m++) {
119
120                             final String JavaDoc r = this.wrappingProcessor.roleManager.getRoleForName(childs[m].getName());
121                             this.sitemapComponentConfigurations.put(r, new ChainedConfiguration(childs[m],
122                                                                              (ChainedConfiguration)this.sitemapComponentConfigurations.get(r)));
123                         }
124                     } else {
125                         // we don't have configurations
126
if ( null == this.wrappingProcessor.parent ) {
127                             this.sitemapComponentConfigurations = Collections.EMPTY_MAP;
128                         } else {
129                             // use configuration from parent
130
this.sitemapComponentConfigurations = this.wrappingProcessor.parent.getComponentConfigurations();
131                         }
132                     }
133                 }
134             }
135         }
136         return this.sitemapComponentConfigurations; }
137
138     /**
139      * Mark this processor as needing to be disposed. Actual call to {@link #dispose()} will occur when
140      * all request processings on this processor will be terminated.
141      */

142     public void markForDisposal() {
143         // Decrement the request count (negative number means dispose)
144
synchronized(this) {
145             this.requestCount--;
146         }
147
148         if (this.requestCount < 0) {
149             // No more users : dispose right now
150
dispose();
151         }
152     }
153
154     public TreeProcessor getWrappingProcessor() {
155         return this.wrappingProcessor;
156     }
157
158     public Processor getRootProcessor() {
159         return this.wrappingProcessor.getRootProcessor();
160     }
161
162     /**
163      * Process the given <code>Environment</code> producing the output.
164      * @return If the processing is successfull <code>true</code> is returned.
165      * If not match is found in the sitemap <code>false</code>
166      * is returned.
167      * @throws org.apache.cocoon.ResourceNotFoundException If a sitemap component tries
168      * to access a resource which can not
169      * be found, e.g. the generator
170      * ConnectionResetException If the connection was reset
171      */

172     public boolean process(Environment environment) throws Exception JavaDoc {
173         InvokeContext context = new InvokeContext();
174         context.enableLogging(getLogger());
175         try {
176             return process(environment, context);
177         } finally {
178             context.dispose();
179         }
180     }
181
182     /**
183      * Process the given <code>Environment</code> to assemble
184      * a <code>ProcessingPipeline</code>.
185      * @since 2.1
186      */

187     public ProcessingPipeline buildPipeline(Environment environment)
188     throws Exception JavaDoc {
189         InvokeContext context = new InvokeContext(true);
190         context.enableLogging(getLogger());
191         try {
192             if (process(environment, context)) {
193                 return context.getProcessingPipeline();
194             } else {
195                 return null;
196             }
197         } finally {
198             context.dispose();
199         }
200     }
201
202     /**
203      * Do the actual processing, be it producing the response or just building the pipeline
204      * @param environment
205      * @param context
206      * @return true if the pipeline was successfully built, false otherwise.
207      * @throws Exception
208      */

209     protected boolean process(Environment environment, InvokeContext context)
210     throws Exception JavaDoc {
211
212             // Increment the concurrent requests count
213
synchronized(this) {
214                 requestCount++;
215             }
216
217             try {
218                 // and now process
219
CocoonComponentManager.enterEnvironment(environment, this.sitemapComponentManager, this);
220
221             Map JavaDoc objectModel = environment.getObjectModel();
222
223             Object JavaDoc oldResolver = objectModel.get(ProcessingNode.OBJECT_SOURCE_RESOLVER);
224                 final Redirector oldRedirector = context.getRedirector();
225
226                 // Build a redirector
227
TreeProcessorRedirector redirector = new TreeProcessorRedirector(environment, context);
228                 setupLogger(redirector);
229                 context.setRedirector(redirector);
230
231             objectModel.put(ProcessingNode.OBJECT_SOURCE_RESOLVER, environment);
232             boolean success = false;
233                 try {
234                     success = this.rootNode.invoke(environment, context);
235
236                     return success;
237
238                 } finally {
239                     CocoonComponentManager.leaveEnvironment(success);
240                     // Restore old redirector and resolver
241
context.setRedirector(oldRedirector);
242                     objectModel.put(ProcessingNode.OBJECT_SOURCE_RESOLVER, oldResolver);
243                 }
244
245             } finally {
246
247                 // Decrement the concurrent request count
248
synchronized(this) {
249                     requestCount--;
250                 }
251
252                 if(requestCount < 0) {
253                     // Marked for disposal and no more concurrent requests.
254
dispose();
255                 }
256             }
257     }
258
259     private boolean handleCocoonRedirect(String JavaDoc uri, Environment environment, InvokeContext context) throws Exception JavaDoc {
260
261         // Build an environment wrapper
262
// If the current env is a facade, change the delegate and continue processing the facade, since
263
// we may have other redirects that will in turn also change the facade delegate
264

265         MutableEnvironmentFacade facade = environment instanceof MutableEnvironmentFacade ?
266             ((MutableEnvironmentFacade)environment) : null;
267
268         if (facade != null) {
269             // Consider the facade delegate (the real environment)
270
environment = facade.getDelegate();
271         }
272
273         // test if this is a call from flow
274
boolean isRedirect = (environment.getObjectModel().remove("cocoon:forward") == null);
275         Environment newEnv = new ForwardEnvironmentWrapper(environment, this.sitemapComponentManager, uri, getLogger());
276         if ( isRedirect ) {
277             ((ForwardEnvironmentWrapper)newEnv).setInternalRedirect(true);
278         }
279
280         if (facade != null) {
281             // Change the facade delegate
282
facade.setDelegate((EnvironmentWrapper)newEnv);
283             newEnv = facade;
284         }
285
286         // Get the processor that should process this request
287
ConcreteTreeProcessor processor;
288         if (newEnv.getRootContext().equals(newEnv.getContext())) {
289             processor = ((TreeProcessor)getRootProcessor()).concreteProcessor;
290         } else {
291             processor = this;
292         }
293
294         // Process the redirect
295
// No more reset since with TreeProcessorRedirector, we need to pop values from the redirect location
296
// context.reset();
297
// The following is a fix for bug #26854 and #26571
298
final boolean result = processor.process(newEnv, context);
299         if ( facade != null ) {
300             newEnv = facade.getDelegate();
301         }
302         if ( ((ForwardEnvironmentWrapper)newEnv).getRedirectURL() != null ) {
303             environment.redirect( false, ((ForwardEnvironmentWrapper)newEnv).getRedirectURL() );
304         }
305         return result;
306     }
307
308     /* (non-Javadoc)
309      * @see org.apache.avalon.framework.activity.Disposable#dispose()
310      */

311     public void dispose() {
312         if (this.disposableNodes != null) {
313             // we must dispose the nodes in reverse order
314
// otherwise selector nodes are freed before the components node
315
for(int i=this.disposableNodes.size()-1; i>-1; i--) {
316                 ((Disposable)disposableNodes.get(i)).dispose();
317             }
318             this.disposableNodes = null;
319         }
320
321         // Ensure it won't be used anymore
322
this.rootNode = null;
323     }
324
325     public String JavaDoc toString() {
326         return "ConcreteTreeProcessor - " + wrappingProcessor.source.getURI();
327     }
328
329     private class TreeProcessorRedirector extends ForwardRedirector {
330
331         private InvokeContext context;
332         public TreeProcessorRedirector(Environment env, InvokeContext context) {
333             super(env);
334             this.context = context;
335         }
336
337         protected void cocoonRedirect(String JavaDoc uri) throws IOException JavaDoc, ProcessingException {
338             try {
339                 ConcreteTreeProcessor.this.handleCocoonRedirect(uri, this.env, this.context);
340             } catch(IOException JavaDoc ioe) {
341                 throw ioe;
342             } catch(ProcessingException pe) {
343                 throw pe;
344             } catch(RuntimeException JavaDoc re) {
345                 throw re;
346             } catch(Exception JavaDoc ex) {
347                 throw new ProcessingException(ex);
348             }
349         }
350     }
351
352     /**
353      * Local extension of EnvironmentWrapper to propagate otherwise blocked
354      * methods to the actual environment.
355      */

356     private static final class ForwardEnvironmentWrapper extends EnvironmentWrapper {
357
358         public ForwardEnvironmentWrapper(Environment env,
359             ComponentManager manager, String JavaDoc uri, Logger logger)
360         throws MalformedURLException JavaDoc {
361             super(env, manager, uri, logger, false);
362         }
363
364         public void setStatus(int statusCode) {
365             environment.setStatus(statusCode);
366         }
367
368         public void setContentLength(int length) {
369             environment.setContentLength(length);
370         }
371
372         public void setContentType(String JavaDoc contentType) {
373             environment.setContentType(contentType);
374         }
375
376         public String JavaDoc getContentType() {
377             return environment.getContentType();
378         }
379
380         public boolean isResponseModified(long lastModified) {
381             return environment.isResponseModified(lastModified);
382         }
383
384         public void setResponseIsNotModified() {
385             environment.setResponseIsNotModified();
386         }
387     }
388 }
389
Popular Tags