KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > sitemap > ContentAggregator


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.sitemap;
17
18 import org.apache.avalon.framework.parameters.Parameters;
19 import org.apache.avalon.framework.service.ServiceException;
20 import org.apache.avalon.framework.service.ServiceManager;
21 import org.apache.avalon.framework.service.Serviceable;
22
23 import org.apache.cocoon.ProcessingException;
24 import org.apache.cocoon.caching.CacheableProcessingComponent;
25 import org.apache.cocoon.components.source.SourceUtil;
26 import org.apache.cocoon.environment.SourceResolver;
27 import org.apache.cocoon.generation.Generator;
28 import org.apache.cocoon.xml.ContentHandlerWrapper;
29 import org.apache.cocoon.xml.XMLConsumer;
30 import org.apache.cocoon.xml.XMLUtils;
31
32 import org.apache.commons.lang.BooleanUtils;
33 import org.apache.excalibur.source.Source;
34 import org.apache.excalibur.source.SourceException;
35 import org.apache.excalibur.source.SourceValidity;
36 import org.apache.excalibur.source.impl.validity.AggregatedValidity;
37 import org.xml.sax.Attributes JavaDoc;
38 import org.xml.sax.SAXException JavaDoc;
39
40 import java.io.IOException JavaDoc;
41 import java.io.Serializable JavaDoc;
42 import java.util.ArrayList JavaDoc;
43 import java.util.Map JavaDoc;
44
45 /**
46  * This generator implements the sitemap content aggregation.
47  * It combines several parts into one big XML document which is streamed
48  * into the pipeline.
49  *
50  * @author <a HREF="mailto:giacomo@apache.org">Giacomo Pati</a>
51  * @author <a HREF="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
52  * @version $Id: ContentAggregator.java 164808 2005-04-26 16:07:03Z vgritsenko $
53  */

54 public class ContentAggregator extends ContentHandlerWrapper
55                                implements Generator, CacheableProcessingComponent,
56                                           Serviceable {
57
58     /** The root element of the aggregated content */
59     protected Element rootElement;
60
61     /** The aggregated parts */
62     protected ArrayList JavaDoc parts = new ArrayList JavaDoc();
63
64     /** Indicates the position in the stack of the root element of the aggregated content */
65     private int rootElementIndex;
66
67     /** The element used for the current part */
68     protected Element currentElement;
69
70     /** The SourceResolver */
71     protected SourceResolver resolver;
72
73     /** The service manager */
74     protected ServiceManager manager;
75
76     /** This object holds the part parts :) */
77     protected static final class Part {
78         public String JavaDoc uri;
79         public Element element;
80         public Source source;
81         boolean stripRootElement;
82
83         public Part(String JavaDoc uri, Element element, String JavaDoc stripRoot) {
84             this.uri = uri;
85             this.element = element;
86             this.stripRootElement = BooleanUtils.toBoolean(stripRoot);
87         }
88     }
89
90     /** This object holds an element definition */
91     protected static final class Element {
92         public String JavaDoc namespace;
93         public String JavaDoc prefix;
94         public String JavaDoc name;
95
96         public Element(String JavaDoc name, String JavaDoc namespace, String JavaDoc prefix) {
97             this.namespace = namespace;
98             this.prefix = prefix;
99             this.name = name;
100         }
101     }
102
103     /**
104      * Generates the content
105      */

106     public void generate()
107     throws IOException JavaDoc, SAXException JavaDoc, ProcessingException {
108         if (getLogger().isDebugEnabled()) {
109             getLogger().debug("Generating aggregated content");
110         }
111         this.contentHandler.startDocument();
112         startElem(this.rootElement);
113
114         try {
115             for (int i = 0; i < this.parts.size(); i++) {
116                 final Part part = (Part) this.parts.get(i);
117                 this.rootElementIndex = part.stripRootElement ? -1 : 0;
118                 if (part.element != null) {
119                     this.currentElement = part.element;
120                     startElem(part.element);
121                 } else {
122                     this.currentElement = this.rootElement;
123                 }
124
125                 try {
126                     SourceUtil.parse(this.manager, part.source, this);
127                 } finally {
128                     if (part.element != null) {
129                         endElem(part.element);
130                     }
131                 }
132             }
133         } finally {
134             endElem(this.rootElement);
135             this.contentHandler.endDocument();
136         }
137         getLogger().debug("Finished aggregating content");
138     }
139
140     /**
141      * Generate the unique key.
142      * This key must be unique inside the space of this component.
143      *
144      * @return The generated key hashes the src
145      */

146     public Serializable JavaDoc getKey() {
147         try {
148             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(64);
149             buffer.append("CA(")
150                     .append(this.rootElement.prefix).append(':')
151                     .append(this.rootElement.name).append('<')
152                     .append(this.rootElement.namespace).append(">)");
153
154             for (int i = 0; i < this.parts.size(); i++) {
155                 final Part part = (Part) this.parts.get(i);
156                 final Source source = part.source;
157
158                 if (part.element == null) {
159                     buffer.append("P=")
160                             .append(part.stripRootElement).append(':')
161                             .append(source.getURI()).append(';');
162                 } else {
163                     buffer.append("P=")
164                             .append(part.element.prefix).append(':')
165                             .append(part.element.name)
166                             .append('<').append(part.element.namespace).append(">:")
167                             .append(part.stripRootElement).append(':')
168                             .append(source.getURI()).append(';');
169                 }
170             }
171
172             return buffer.toString();
173         } catch (Exception JavaDoc e) {
174             getLogger().error("Could not generateKey", e);
175             return null;
176         }
177     }
178
179     /**
180      * Generate the validity object.
181      *
182      * @return The generated validity object or <code>null</code> if the
183      * component is currently not cacheable.
184      */

185     public SourceValidity getValidity() {
186         try {
187             AggregatedValidity v = new AggregatedValidity();
188             for (int i = 0; i < this.parts.size(); i++) {
189                 final Source current = ((Part) this.parts.get(i)).source;
190                 final SourceValidity sv = current.getValidity();
191
192                 if (sv == null) {
193                     return null;
194                 } else {
195                     v.add(sv);
196                 }
197             }
198
199             return v;
200         } catch (Exception JavaDoc e) {
201             getLogger().error("Could not getValidity", e);
202             return null;
203         }
204     }
205
206     /**
207      * Set the root element. Please make sure that the parameters are not null!
208      */

209     public void setRootElement(String JavaDoc element, String JavaDoc namespace, String JavaDoc prefix) {
210         this.rootElement = new Element(element,
211                                        namespace,
212                                        prefix);
213         if (getLogger().isDebugEnabled()) {
214             getLogger().debug("Root element='" + element +
215                               "' ns='" + namespace + "' prefix='" + prefix + "'");
216         }
217     }
218
219     /**
220      * Add a part. Please make sure that the parameters are not null!
221      */

222     public void addPart(String JavaDoc uri,
223                         String JavaDoc element,
224                         String JavaDoc namespace,
225                         String JavaDoc stripRootElement,
226                         String JavaDoc prefix) {
227         Element elem = null;
228         if (!element.equals("")) {
229             if (namespace.equals("")) {
230                 elem = new Element(element,
231                                    this.rootElement.namespace,
232                                    this.rootElement.prefix);
233             } else {
234                 elem = new Element(element,
235                                    namespace,
236                                    prefix);
237             }
238         }
239         this.parts.add(new Part(uri,
240                                 elem,
241                                 stripRootElement));
242         if (getLogger().isDebugEnabled()) {
243             getLogger().debug("Part uri='" + uri +
244                               "' element='" + element + "' ns='" + namespace +
245                               "' stripRootElement='" + stripRootElement + "' prefix='" + prefix + "'");
246         }
247     }
248
249     /**
250      * Set the <code>XMLConsumer</code> that will receive XML data.
251      *
252      * <br>
253      * This method will simply call <code>setContentHandler(consumer)</code>
254      * and <code>setLexicalHandler(consumer)</code>.
255      */

256     public void setConsumer(XMLConsumer consumer) {
257         setContentHandler(consumer);
258         setLexicalHandler(consumer);
259     }
260
261     /**
262      * Recycle the producer by removing references
263      */

264     public void recycle() {
265         super.recycle();
266
267         this.rootElement = null;
268         for (int i = 0; i < this.parts.size(); i++) {
269             final Part current = (Part) this.parts.get(i);
270             if (current.source != null) {
271                 if (getLogger().isDebugEnabled()) {
272                     getLogger().debug("Releasing " + current.source);
273                 }
274                 this.resolver.release(current.source);
275             }
276         }
277         this.parts.clear();
278         this.currentElement = null;
279         this.resolver = null;
280     }
281
282     /**
283      * Set the <code>SourceResolver</code>, object model <code>Map</code>,
284      * the source and sitemap <code>Parameters</code> used to process the request.
285      */

286     public void setup(SourceResolver resolver, Map JavaDoc objectModel, String JavaDoc src, Parameters par)
287     throws ProcessingException, SAXException JavaDoc, IOException JavaDoc {
288         this.resolver = resolver;
289         // get the Source for each part
290
try {
291             for (int i = 0; i < this.parts.size(); i++) {
292                 final Part current = (Part) this.parts.get(i);
293                 current.source = resolver.resolveURI(current.uri);
294             }
295         } catch (SourceException se) {
296             throw SourceUtil.handle("Unable to resolve source.", se);
297         }
298     }
299
300     /**
301      * Private method generating startElement event for the aggregated parts
302      * and the root element
303      */

304     private void startElem(Element element)
305     throws SAXException JavaDoc {
306         final String JavaDoc qname = (element.prefix.equals("")) ? element.name : element.prefix + ':' + element.name;
307         if (!element.namespace.equals("")) {
308             this.contentHandler.startPrefixMapping(element.prefix, element.namespace);
309         }
310         this.contentHandler.startElement(element.namespace, element.name, qname, XMLUtils.EMPTY_ATTRIBUTES);
311     }
312
313     /**
314      * Private method generating endElement event for the aggregated parts
315      * and the root element
316      */

317     private void endElem(Element element) throws SAXException JavaDoc {
318         final String JavaDoc qname = (element.prefix.equals("")) ? element.name : element.prefix + ':' + element.name;
319         this.contentHandler.endElement(element.namespace, element.name, qname);
320         if (!element.namespace.equals("")) {
321             this.contentHandler.endPrefixMapping(element.prefix);
322         }
323     }
324
325     /**
326      * Ignore start and end document events
327      */

328     public void startDocument() throws SAXException JavaDoc {
329     }
330
331     /**
332      * Ignore start and end document events
333      */

334     public void endDocument() throws SAXException JavaDoc {
335     }
336
337     /**
338      * Override startElement() event to add namespace and prefix
339      */

340     public void startElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc raw, Attributes JavaDoc atts)
341     throws SAXException JavaDoc {
342         this.rootElementIndex++;
343         if (this.rootElementIndex == 0) {
344             getLogger().debug("Skipping root element start event.");
345             return;
346         }
347         if (namespaceURI == null || namespaceURI.equals("")) {
348             final String JavaDoc qname = this.currentElement.prefix.equals("") ? localName : this.currentElement.prefix + ':' + localName;
349             this.contentHandler.startElement(this.currentElement.namespace, localName, qname, atts);
350         } else {
351             this.contentHandler.startElement(namespaceURI, localName, raw, atts);
352         }
353     }
354
355     /**
356      * Override startElement() event to add namespace and prefix
357      */

358     public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc raw) throws SAXException JavaDoc {
359         this.rootElementIndex--;
360         if (this.rootElementIndex == -1) {
361             getLogger().debug("Skipping root element end event.");
362             return;
363         }
364         if (namespaceURI == null || namespaceURI.equals("")) {
365             final String JavaDoc qname = this.currentElement.prefix.equals("") ? localName : this.currentElement.prefix + ':' + localName;
366             this.contentHandler.endElement(this.currentElement.namespace, localName, qname);
367         } else {
368             this.contentHandler.endElement(namespaceURI, localName, raw);
369         }
370     }
371
372     /* (non-Javadoc)
373      * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
374      */

375     public void service(ServiceManager manager) throws ServiceException {
376         this.manager = manager;
377     }
378 }
379
Popular Tags