KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > generation > ServerPagesGenerator


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.generation;
17
18 import org.apache.commons.collections.ArrayStack;
19 import org.apache.avalon.framework.activity.Disposable;
20 import org.apache.avalon.framework.component.ComponentException;
21 import org.apache.avalon.framework.component.ComponentManager;
22 import org.apache.avalon.framework.configuration.Configurable;
23 import org.apache.avalon.framework.configuration.Configuration;
24 import org.apache.avalon.framework.configuration.ConfigurationException;
25 import org.apache.avalon.framework.parameters.Parameters;
26 import org.apache.cocoon.ProcessingException;
27 import org.apache.cocoon.ResourceNotFoundException;
28 import org.apache.cocoon.caching.CacheableProcessingComponent;
29 import org.apache.cocoon.components.language.generator.ProgramGenerator;
30 import org.apache.cocoon.components.source.SourceUtil;
31 import org.apache.cocoon.environment.SourceResolver;
32 import org.apache.cocoon.xml.AbstractXMLPipe;
33 import org.apache.excalibur.source.Source;
34 import org.apache.excalibur.source.SourceException;
35 import org.apache.excalibur.source.SourceValidity;
36 import org.xml.sax.Attributes JavaDoc;
37 import org.xml.sax.SAXException JavaDoc;
38
39 import java.io.IOException JavaDoc;
40 import java.io.Serializable JavaDoc;
41 import java.util.Map JavaDoc;
42
43 /**
44  * This class acts as a proxy to a dynamically loaded<code>Generator</code>
45  * delegating actual SAX event generation.
46  * <p>
47  * It has a single configuration item :
48  * <code>&lt;autocomplete-documents&gttrue|false&lt;autocomplete-documents&gt;</code>
49  * (default is <code>false</code>).
50  * <p>
51  * This tells the generator to automatically close all elements that weren't properly closed
52  * by the XSP, such as when a <code>return</code> statement is used to prematurely end
53  * processing. Activating this feature <em>sensibly increases CPU-usage</em> and should
54  * therefore be used only if really needed (it's better to have clean XSP pages that don't
55  * break abruptly generation flow).
56  *
57  * @author <a HREF="mailto:ricardo@apache.org">Ricardo Rocha</a>
58  * @author <a HREF="mailto:sylvain@apache.org">Sylvain Wallez</a>
59  * @version CVS $Id: ServerPagesGenerator.java 30932 2004-07-29 17:35:38Z vgritsenko $
60  */

61 public class ServerPagesGenerator extends ServletGenerator
62         implements Disposable, CacheableProcessingComponent, Configurable {
63     /**
64      * The sitemap-defined server pages program generator
65      */

66     protected ProgramGenerator programGenerator = null;
67
68     protected AbstractServerPage generator = null;
69
70     /** The source */
71     private Source inputSource;
72
73     private CompletionPipe completionPipe;
74
75     /**
76      * Set the global component manager. This method sets the sitemap-defined
77      * program generator
78      *
79      * @param manager The global component manager
80      */

81     public void compose(ComponentManager manager) throws ComponentException {
82         super.compose(manager);
83
84         if (programGenerator == null) {
85             this.programGenerator =
86                     (ProgramGenerator) manager.lookup(ProgramGenerator.ROLE);
87         }
88     }
89
90     public void configure(Configuration config) throws ConfigurationException {
91         boolean autoComplete = config.getChild("autocomplete-documents").getValueAsBoolean(false);
92
93         if (autoComplete) {
94             this.completionPipe = new CompletionPipe();
95             this.completionPipe.enableLogging(getLogger());
96         }
97
98         this.markupLanguage = config.getChild("markup-language").getValue(DEFAULT_MARKUP_LANGUAGE);
99         this.programmingLanguage = config.getChild("programming-language").getValue(DEFAULT_PROGRAMMING_LANGUAGE);
100     }
101
102     /**
103      * Generate the unique key.
104      * This key must be unique inside the space of this component.
105      * This method must be invoked before the generateValidity() method.
106      *
107      * @return The generated key or <code>null</code> if the component
108      * is currently not cacheable.
109      */

110     public Serializable JavaDoc getKey() {
111         Object JavaDoc key = generator.getKey();
112         if (key == null) {
113             return this.inputSource.getURI();
114         }
115         return this.inputSource.getURI() + '-' + key;
116     }
117
118     /**
119      * Generate the validity object.
120      * Before this method can be invoked the generateKey() method
121      * must be invoked.
122      *
123      * @return The generated validity object or <code>null</code> if the
124      * component is currently not cacheable.
125      */

126     public SourceValidity getValidity() {
127         // VG: Input source's systemID is part of the key,
128
// and need not be included into the validity.
129
return generator.getValidity();
130     }
131
132     /**
133      * The loaded generator's <code>MarkupLanguage</code>
134      */

135     protected String JavaDoc markupLanguage;
136
137     /**
138      * The loaded generator's <code>ProgrammingLanguage</code>
139      */

140     protected String JavaDoc programmingLanguage;
141
142     /**
143      * The default <code>MarkupLanguage</code>
144      */

145     public final static String JavaDoc DEFAULT_MARKUP_LANGUAGE = "xsp";
146
147     /**
148      * The default <code>ProgrammingLanguage</code>
149      */

150     public final static String JavaDoc DEFAULT_PROGRAMMING_LANGUAGE = "java";
151
152     public void setup(SourceResolver resolver, Map JavaDoc objectModel, String JavaDoc src, Parameters par)
153             throws ProcessingException, SAXException JavaDoc, IOException JavaDoc {
154
155         super.setup(resolver, objectModel, src, par);
156
157         String JavaDoc markupLanguage = this.parameters.getParameter(
158                 "markup-language", this.markupLanguage);
159         String JavaDoc programmingLanguage = this.parameters.getParameter(
160                 "programming-language", this.programmingLanguage);
161
162         try {
163             this.inputSource = this.resolver.resolveURI(src);
164         } catch (SourceException se) {
165             throw SourceUtil.handle("Error during resolving of '" + src + "'.", se);
166             //throw SourceUtil.handle(se);
167
}
168
169         try {
170             this.generator = (AbstractServerPage) programGenerator.load(this.manager,
171                     this.inputSource, markupLanguage, programmingLanguage, this.resolver);
172         } catch (ProcessingException e) {
173             throw e;
174         } catch (Exception JavaDoc e) {
175             getLogger().warn("setup()", e);
176             throw new ProcessingException(e.getMessage(), e);
177         } catch (NoClassDefFoundError JavaDoc e) {
178             // VG: Usually indicates that page invoked with the wrong case.
179
// I.e., it was compiled as "my.xsp" and inoked as "My.xsp",
180
// results in different class name and an error.
181
getLogger().warn("Failed to load class: " + e);
182             throw new ResourceNotFoundException(e.getMessage());
183         }
184
185         // Give our own logger to the generator so that logs go in the correct category
186
generator.enableLogging(getLogger());
187
188         generator.setup(super.resolver, super.objectModel, super.source, super.parameters);
189     }
190
191     /**
192      * Generate XML data. This method loads a server pages generator associated
193      * with its (file) input source and delegates SAX event generator to it
194      * taking care of "closing" any event left open by the loaded generator as a
195      * result of its possible "premature" return (a common situation in server
196      * pages)
197      *
198      * @exception IOException IO Error
199      * @exception SAXException SAX event generation error
200      * @exception ProcessingException Error during load/execution
201      */

202     public void generate() throws IOException JavaDoc, SAXException JavaDoc, ProcessingException {
203
204         if (this.completionPipe != null) {
205             generator.setConsumer(this.completionPipe);
206             if (this.xmlConsumer != null) {
207                 this.completionPipe.setConsumer(this.xmlConsumer);
208             } else {
209                 this.completionPipe.setContentHandler(this.contentHandler);
210                 this.completionPipe.setLexicalHandler(this.lexicalHandler);
211             }
212         } else {
213             if (this.xmlConsumer != null) {
214                 generator.setConsumer(this.xmlConsumer);
215             } else {
216                 generator.setContentHandler(this.contentHandler);
217                 generator.setLexicalHandler(this.lexicalHandler);
218             }
219         }
220
221         // Fixes BUG#4062: Set document locator which is used by XIncludeTransformer
222
org.xml.sax.helpers.LocatorImpl JavaDoc locator = new org.xml.sax.helpers.LocatorImpl JavaDoc();
223         locator.setSystemId(this.inputSource.getURI());
224         this.contentHandler.setDocumentLocator(locator);
225
226         // Log exception and ensure that generator is released.
227
try {
228             generator.generate();
229         } catch (IOException JavaDoc e) {
230             getLogger().debug("IOException in generate()", e);
231             throw e;
232         } catch (SAXException JavaDoc e) {
233             getLogger().debug("SAXException in generate()", e);
234             throw e;
235         } catch (ProcessingException e) {
236             getLogger().debug("ProcessingException in generate()", e);
237             throw e;
238         } catch (Exception JavaDoc e) {
239             getLogger().debug("Exception in generate()", e);
240             throw new ProcessingException("Exception in ServerPagesGenerator.generate()", e);
241         } finally {
242             if (generator != null) {
243                 programGenerator.release(generator);
244             }
245             generator = null;
246         }
247
248         if (this.completionPipe != null) {
249             this.completionPipe.flushEvents();
250         }
251     }
252
253     /**
254      * Recycle the generator by removing references
255      */

256     public void recycle() {
257         if (this.generator != null) {
258             this.programGenerator.release(this.generator);
259             this.generator = null;
260         }
261         if (this.inputSource != null) {
262             this.resolver.release(this.inputSource);
263             this.inputSource = null;
264         }
265         if (this.completionPipe != null) {
266             this.completionPipe.recycle();
267             this.completionPipe = null;
268         }
269         super.recycle();
270     }
271
272     /**
273      * dispose
274      */

275     public void dispose() {
276         this.manager.release(this.programGenerator);
277         this.programGenerator = null;
278         this.manager = null;
279     }
280
281     /* Completion pipe */
282
283     // int values for event types
284
private final static int DOCUMENT = 0;
285     private final static int ELEMENT = 1;
286     private final static int PREFIX_MAPPING = 2;
287     private final static int CDATA = 3;
288     private final static int DTD = 4;
289     private final static int ENTITY = 5;
290
291     // Integer equivalents to push on the stack
292
private final static Integer JavaDoc DOCUMENT_OBJ = new Integer JavaDoc(DOCUMENT);
293     private final static Integer JavaDoc ELEMENT_OBJ = new Integer JavaDoc(ELEMENT);
294     private final static Integer JavaDoc PREFIX_MAPPING_OBJ = new Integer JavaDoc(PREFIX_MAPPING);
295     private final static Integer JavaDoc CDATA_OBJ = new Integer JavaDoc(CDATA);
296     private final static Integer JavaDoc DTD_OBJ = new Integer JavaDoc(DTD);
297     private final static Integer JavaDoc ENTITY_OBJ = new Integer JavaDoc(ENTITY);
298
299     public class CompletionPipe extends AbstractXMLPipe {
300
301         /**
302          * The SAX event stack. Used for "completing" pendind SAX events left "open"
303          * by prematurely returning server pages generators
304          */

305         protected ArrayStack eventStack = new ArrayStack();
306
307         /**
308          * Receive notification of the beginning of a document.
309          */

310         public void startDocument() throws SAXException JavaDoc {
311             super.startDocument();
312             this.eventStack.push(DOCUMENT_OBJ);
313         }
314
315         /**
316          * Receive notification of the end of a document.
317          */

318         public void endDocument() throws SAXException JavaDoc {
319             this.eventStack.pop();
320             super.endDocument();
321         }
322
323         /**
324          * Receive notification of the beginning of an element.
325          */

326         public void startElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc rawName, Attributes JavaDoc atts)
327                 throws SAXException JavaDoc {
328             super.startElement(namespaceURI, localName, rawName, atts);
329             this.eventStack.push(rawName);
330             this.eventStack.push(localName);
331             this.eventStack.push(namespaceURI);
332             this.eventStack.push(ELEMENT_OBJ);
333         }
334
335         /**
336          * Receive notification of the end of an element.
337          */

338         public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc rawName)
339                 throws SAXException JavaDoc {
340             this.eventStack.pop(); // ELEMENT_OBJ
341
this.eventStack.pop(); // namespaceURI
342
this.eventStack.pop(); // localName
343
this.eventStack.pop(); // rawName
344
super.endElement(namespaceURI, localName, rawName);
345         }
346
347         /**
348          * Begin the scope of a prefix-URI Namespace mapping.
349          */

350         public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri) throws SAXException JavaDoc {
351             super.startPrefixMapping(prefix, uri);
352             this.eventStack.push(prefix);
353             this.eventStack.push(PREFIX_MAPPING_OBJ);
354         }
355
356         /**
357          * End the scope of a prefix-URI mapping.
358          */

359         public void endPrefixMapping(String JavaDoc prefix) throws SAXException JavaDoc {
360             this.eventStack.pop(); // PREFIX_MAPPING_OBJ
361
this.eventStack.pop(); // prefix
362
super.endPrefixMapping(prefix);
363         }
364
365         public void startCDATA() throws SAXException JavaDoc {
366             super.startCDATA();
367             this.eventStack.push(CDATA_OBJ);
368         }
369
370         public void endCDATA() throws SAXException JavaDoc {
371             this.eventStack.pop();
372             super.endCDATA();
373         }
374
375         public void startDTD(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
376                 throws SAXException JavaDoc {
377             super.startDTD(name, publicId, systemId);
378             this.eventStack.push(DTD_OBJ);
379         }
380
381         public void endDTD() throws SAXException JavaDoc {
382             this.eventStack.pop();
383             super.endDTD();
384         }
385
386         public void startEntity(String JavaDoc name) throws SAXException JavaDoc {
387             super.startEntity(name);
388             this.eventStack.push(name);
389             this.eventStack.push(ENTITY_OBJ);
390         }
391
392         public void endEntity(String JavaDoc name) throws SAXException JavaDoc {
393             this.eventStack.pop(); // ENTITY_OBJ
394
this.eventStack.pop(); // name
395
super.endEntity(name);
396         }
397
398         public void flushEvents() throws SAXException JavaDoc {
399
400             if (this.getLogger().isWarnEnabled()) {
401                 if (this.eventStack.size() > 0) {
402                     this.getLogger().warn("Premature end of document generated by " + inputSource.getURI());
403                 }
404             }
405
406             // End any started events in case of premature return
407
while (this.eventStack.size() != 0) {
408                 int event = ((Integer JavaDoc) eventStack.pop()).intValue();
409
410                 switch (event) {
411                     case DOCUMENT:
412                         super.endDocument();
413                         break;
414
415                     case ELEMENT:
416                         String JavaDoc namespaceURI = (String JavaDoc) eventStack.pop();
417                         String JavaDoc localName = (String JavaDoc) eventStack.pop();
418                         String JavaDoc rawName = (String JavaDoc) eventStack.pop();
419                         super.endElement(namespaceURI, localName, rawName);
420                         break;
421
422                     case PREFIX_MAPPING:
423                         super.endPrefixMapping((String JavaDoc) eventStack.pop());
424                         break;
425
426                     case CDATA:
427                         super.endCDATA();
428                         break;
429
430                     case DTD:
431                         super.endDTD();
432                         break;
433
434                     case ENTITY:
435                         super.endEntity((String JavaDoc) eventStack.pop());
436                         break;
437                 }
438             }
439         }
440
441         public void recycle() {
442             this.eventStack.clear();
443             super.recycle();
444         }
445     }
446 }
447
Popular Tags